基本类型拷贝:

克隆是针对于对象而言的,基本类型(boolean,char,byte,short,float,double.long)已久具备自身克隆的特性.

    int x=;
int y=x;
System.out.println(x);//
System.out.println(y);//
y=;
System.out.println(x);//
System.out.println(y);//

JVM实现拷贝的目的:

大家先思考一个问题,为什么需要克隆对象?直接 new 一个对象不行吗?

  答案是:克隆的对象可能包含一些已经修改过的属性,而 new 出来的对象的属性都还是初始化时候的值,所以当需要一个新的对象来保存当前对象的 “状态” 就靠 clone 方法了。那么我把这个对象的临时属性一个一个的赋值给我新 new 的对象不也行嘛?

可以是可以,但是一来麻烦不说,二来,大家通过上面的源码都发现了 clone 是一个 native 方法,就是快啊,在底层实现的

引用的拷贝

 //引用拷贝
private static void copyReferenceObject(){
Person p = new Person(23, "zhang");
Person p1 = p;
System.out.println(p);
System.out.println(p1);
}

这里打印的结果: 
Person@3654919e 
Person@3654919e 
可以看到,打印的结果是一样的,也就是说,二者的引用是同一个对象,并没有创建出一个新的对象。因此要区分引用拷贝和对象拷贝的区别,下面要介绍的就是对象拷贝。

浅拷贝

  • 如果pojo中存在的是基本数据类型 ,String 除外 ,实现Cloneable 覆写Clone 方法 这个就是浅拷贝

- code

 package core.java.deeporshoawcopy;

 /**
* @author DGW-PC
* @date 2018年6月7日
* @see 验证 浅拷贝 一般要求实体类使用包装类型 对于深拷贝 类中存在对其他类的引用,也需要实现cloneable接口
*/ class Person implements Cloneable{
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
protected Object clone() throws CloneNotSupportedException {
/*Person p=null;
try{
p=(Person) super.clone();
}catch (CloneNotSupportedException e) {
}*/
return super.clone();
}
} public class Base { public static void main(String[] args) throws CloneNotSupportedException {
Person person = new Person();
person.setName("a");
person.setAge(12);
Person per1=(Person) person.clone();
per1.setName("b");
per1.setAge(14);;
System.out.println(person.getName()+" "+person.getAge().hashCode(0));
System.out.println(per1.getName()+" "+per1.getAge());
} }

 内存图:

深拷贝

- 如果你的POJO 存在的不是基本上数据类型,可以是自己定义类型,也可以其他包提供的类型 这里以java 提供的Data 的为例子 可以看下面的代码 自身实现clone 方法 你在涉及到使用拷贝的时候一定要注意别的包提供的类是否出现了问题

  /**
* Return a copy of this object.
*/
public Object clone() {
Date d = null;
try {
d = (Date)super.clone();
if (cdate != null) {
d.cdate = (BaseCalendar.Date) cdate.clone();
}
} catch (CloneNotSupportedException e) {} // Won't happen
return d;
}

- 下面介绍一下基本深拷贝的代码 很短 : 你一定主要 主类包装了多少其他的引用类型的其他类,那么其他必须都要实现Cloneable 接口 以及clone (保护方法) 方法

方法原型:

仔细一看,它还是一个 native 方法,大家都知道 native 方法是非 Java 语言实现的代码,供 Java 程序调用的,

因为 Java 程序是运行在 JVM 虚拟机上面的,要想访问到比较底层的与操作系统相关的就没办法了,只能由靠近操作系统的语言来实现

/*
2Creates and returns a copy of this object. The precise meaning of "copy" may depend on the class of the object.
3The general intent is that, for any object x, the expression:
41) x.clone() != x will be true
52) x.clone().getClass() == x.getClass() will be true, but these are not absolute requirements.
63) x.clone().equals(x) will be true, this is not an absolute requirement.
7*/protected native Object clone() throws CloneNotSupportedException;

需要满足的条件:

  对于任何对象x,表达式:

  • 1)x.clone()!= x将为真
  • 2)x.clone()。getClass()== x.getClass()为true,但这不是绝对要求。
  • 3)x.clone()。equals(x)将为true,这不是绝对要求。

具体代码:

 package core.java.deeporshoawcopy;

 /**
* @author DGW-PC
* @date 2018年6月7日
* @see 实现序列化 深拷贝
*/ class Dog implements Cloneable{
private String name; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class User implements Cloneable{
private String name;
private Dog dog;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
protected Object clone() throws CloneNotSupportedException {
User u=(User) super.clone();
u.dog=(Dog) dog.clone(); //多个需要在全部把关系搞清楚
return u;
}
} public class ObjCloner {
public static void main(String[] args) throws CloneNotSupportedException {
Dog dog = new Dog();
dog.setName("田园犬");
User user = new User();
user.setDog(dog);
user.setName("王二");
User user1=(User) user.clone();
user1.setName("张三");
Dog dog2 = new Dog();
dog2.setName("德国牧羊犬");
user1.setDog(dog2);
System.out.println(user.getName()+"养了"+ user.getDog().getName());
System.out.println(user1.getName()+"养了"+ user1.getDog().getName());
}
}

结果:

类组合形式下深拷贝

 class Car implements Cloneable{
String name; public Car(String name) {
this.name = name;
}
@Override
protected Object clone() {
Car car=null;
try {
car=(Car) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return car;
}
@Override
public String toString() {
return "Car [name=" + name + "]";
}
}
class Home implements Cloneable{
String name;
public Home(String name) {
this.name = name;
}
@Override
protected Object clone() {
Home home=null;
try {
home=(Home) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return home;
}
@Override
public String toString() {
return "Home [name=" + name + "]";
}
}
class Wife implements Cloneable{
String name;
public Wife(String name) {
this.name = name;
}
@Override
protected Object clone() {
Wife wife=null;
try {
wife=(Wife) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return wife;
}
@Override
public String toString() {
return "Wife [name=" + name + "]";
}
}
class Person implements Cloneable{
String name;
Car car;
Home home;
Wife wife;
public Person(String name, Car car, Home home, Wife wife) {
super();
this.name = name;
this.car = car;
this.home = home;
this.wife = wife;
}
@Override
public String toString() {
return "Person [name=" + name + ", car=" + car + ", home=" + home + ", wife=" + wife + "]";
}
@Override
protected Object clone() {
Person person=null;
try {
person=(Person) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
person.car=(Car) this.car.clone();
person.home=(Home) this.home.clone();
person.wife=(Wife) this.wife.clone();
return person;
} } public class Test2 {
public static void main(String[] args) {
Person person = new Person("Tom", new Car("bmw"), new Home("一环以内"), new Wife("intkk"));
//Person person1=person;
Person person1 = (Person) person.clone();
System.out.println(person);
System.out.println(person1);
person1.name="Jerry";
person1.home= new Home("帝国");
person1.car=new Car("五菱骨灰盒");
System.out.println(person);
System.out.println(person1);
}
}

问题: 当存在多个类的时候,每个类都要实现Clonebale接口,实现过于复杂: 特别是下面这段代码: (当多个类的时候建议使用串行化方式进行clone)

    protected Object clone()  {
Person person=null;
try {
person=(Person) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
person.car=(Car) this.car.clone();
person.home=(Home) this.home.clone();
person.wife=(Wife) this.wife.clone();
return person;
}

串行化方式实现深拷贝

  实现方法:

  •   实现Serializable接口,如果类中存在组合形式的使用,那么每个类都要实现Serializable接口

- 以下代码着重注意一下 CloneObj方法 ,就行。

 package core.java.deeporshoawcopy;

 import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable; /**
* @author DGW-PC
* @date 2018年6月7日
* @since 串行化 实现 深拷贝
*/ class Body implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
private Fonter fonter;
private Head head;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Fonter getFonter() {
return fonter;
}
public void setFonter(Fonter fonter) {
this.fonter = fonter;
}
public Head getHead() {
return head;
}
public void setHead(Head head) {
this.head = head;
}
@Override
public String toString() {
return "Body [name=" + name + ", fonter=" + fonter + ", head=" + head + "]";
}
public Body(String name, Fonter fonter, Head head) {
super();
this.name = name;
this.fonter = fonter;
this.head = head;
} }
class Head implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer size;
}
class Fonter implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer size;
}
class Face implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer size;
}
public class ObjClonerSeiz { private static <T>T CloneObj(T obj){
T retobj=null;
try {
//写入流中
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
//从流中读取
ObjectInputStream ios = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
retobj=(T) ios.readObject();
}catch (Exception e) {
e.printStackTrace();
}
return retobj;
} public static void main(String[] args) {
Body body = new Body("张三", new Fonter(), new Head());
Body body2=CloneObj(body);
System.out.println("body==body2 ====>"+(body==body2));
System.out.println("body.font==body2.font ====>"+(body.getFonter()==body2.getFonter()));
System.out.println("body.head==body2.head ====>"+(body.getHead()==body2.getHead()));
}
}

总结:

  • 在Java语言中,如果需要实现深克隆,可以通过覆盖Object类的clone()方法实现,也可以通过序列化(Serialization)等方式来实现。
  • 如果引用类型里面还包含很多引用类型,或者内层引用类型的类里面又包含引用类型,使用clone方法就会很麻烦。这时我们可以用序列化的方式来实现对象的深克隆。)
  • 实现对象克隆有两种方式:

      1). 实现Cloneable接口并重写Object类中的clone()方法;

      2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆

Java中对象拷贝的两种方式的更多相关文章

  1. Java中HashMap遍历的两种方式

    Java中HashMap遍历的两种方式 转]Java中HashMap遍历的两种方式原文地址: http://www.javaweb.cc/language/java/032291.shtml 第一种: ...

  2. java中数组复制的两种方式

    在java中数组复制有两种方式: 一:System.arraycopy(原数组,开始copy的下标,存放copy内容的数组,开始存放的下标,需要copy的长度); 这个方法需要先创建一个空的存放cop ...

  3. java中实现同步的两种方式:syschronized和lock的区别和联系

    Lock是java.util.concurrent.locks包下的接口,Lock 实现提供了比使用synchronized 方法和语句可获得的更广泛的锁定操作,它能以更优雅的方式处理线程同步问题,我 ...

  4. Java中实现多线程的两种方式之间的区别

    Java提供了线程类Thread来创建多线程的程序.其实,创建线程与创建普通的类的对象的操作是一样的,而线程就是Thread类或其子类的实例对象.每个Thread对象描述了一个单独的线程.要产生一个线 ...

  5. Java中创建String的两种方式

    1.在Java中,创建一个字符串有两种方式 String x = "abc";String y = new String("abc"); 这两种方式有什么区别呢 ...

  6. java中设置代理的两种方式

    1 前言 有时候我们的程序中要提供可以使用代理访问网络,代理的方式包括http.https.ftp.socks代理.比如在IE浏览器设置代理. 那我们在我们的java程序中使用代理呢,有如下两种方式. ...

  7. java中创建字符串的两种方式(“”与new String())及区别

    结论:通过""创建的字符串实际上在java堆中只有一个,而通过new string创建出来的字符串在java堆中占有不同的内存. 第一个True表明这两个在内存中拥有相同的地址,那 ...

  8. Java中实现序列化的两种方式 Serializable 接口和 Externalizable接口

    对象的序列化就是将对象写入输出流中. 反序列化就是从输入流中将对象读取出来. 用来实现序列化的类都在java.io包中,我们常用的类或接口有: ObjectOutputStream:提供序列化对象并把 ...

  9. java中String初始化的两种方式

    转自:http://www.diybl.com/course/3_program/java/javajs/2007104/75886.html       字符串可能是任何程序语言中都会出现的对象,j ...

随机推荐

  1. OpenGL几何变换---翻译http://www.songho.ca/opengl/gl_projectionmatrix.html

    Overview 几何数据——顶点位置,和法向量(normal vectors),在OpenGL 管道raterization 处理过程之前可通过顶点运算(Vertex Operation)和基本组合 ...

  2. vim 编辑器IDE版

    wget https://raw.github.com/ma6174/vim/master/setup.sh -O ma6174_vim_setup.sh && bash ma6174 ...

  3. BZOJ_5338_ [TJOI2018]xor_可持久化trie

    BZOJ_5338_ [TJOI2018]xor_可持久化trie Description 有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并 ...

  4. ACM学习历程—BestCoder 2015百度之星资格赛1001 大搬家(递推 && 组合数学)

    Problem Description 近期B厂组织了一次大搬家,所有人都要按照指示换到指定的座位上.指示的内容是坐在位置i 上的人要搬到位置j 上.现在B厂有N 个人,一对一到N 个位置上.搬家之后 ...

  5. Excel 2007无法打开多个窗口的问题

    Excel 2007使用的时候打开多个工作薄的时候,不像2003那样默认独立分开窗口显示.要切换工作簿,需要通过 “视图-切换窗口”来选择需要当前活动的窗口,这样的操作给同时操作多个工作薄来说,非常不 ...

  6. [RTOS]--uCOS、FreeRTOS、RTThread、RTX等RTOS的对比之特点

    本篇博客就来细数这几个RTOS的特点.   以下内容均来自官方网站或者官方手册Feature的Google翻译的加了我的一些调整,没有任何主观成分. 1. FreeRTOS   FreeRTOS是专为 ...

  7. ActiveRecord 的类型初始值设定项引发异常

    最近在研究ActiveRecord网上有很多贴子讲怎么用的.但自己照做就是出错. 最终定位在配置文件出错.应该是ActiveRecord有更新的原因.在国外的网站把配置复制了一份替换.问题解决了.我用 ...

  8. ASP.NET中 TextBox 文本输入框控件的使用方法

    TextBox控件又称文本框控件,为用户提供输入文本的功能. 1.属性 TextBox控件的常用属性及说明如表1所示. 表1 TextBox控件常用属性及说明 属性 说明 AutoPostBack 获 ...

  9. Django ORM 那些相关操作

    Django ORM 那些相关操作 一般操作 必知必会13条 <> all(): #查询所有的结果 <> filter(**kwargs) # 它包含了与所给筛选条件相匹配的对 ...

  10. 注册美国iTunes账号步骤(跳过绑定银行卡)

    步骤: 将iTunes客户端升级到最新版本 注销当前登陆的用户,随便搜索一个免费的应用 点击下载,此时会弹框提示你登陆,点击下方注册超链 跳转到注册页面,同意各种条款,点击下一步 填写邮箱(最好用gm ...