精华内容
下载资源
问答
  • Java对象拷贝(对象克隆 对象复制) 1.前言 假如说你想复制一个简单变量。很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short,float,double.long)同样...

    Java对象拷贝(对象克隆 对象复制)

    1.前言

    假如说你想复制一个简单变量。很简单:

    int apples = 5;  
    int pears = apples;  
    

    不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short,float,double.long)同样适用于该类情况。

    但是如果你复制的是一个对象,情况就有些复杂了。

    但假如是个新手,可能会这样写。

    class Student {  
        private int number;  
      
        public int getNumber() {  
            return number;  
        }  
      
        public void setNumber(int number) {  
            this.number = number;  
        }  
          
    }  
    public class Test {  
          
        public static void main(String args[]) {  
            Student stu1 = new Student();  
            stu1.setNumber(12345);  
            Student stu2 = stu1;  
              
            System.out.println("学生1:" + stu1.getNumber());  
            System.out.println("学生2:" + stu2.getNumber());  
        }  
    }
    

    结果:

    学生1:12345

    学生2:12345

    但我们试着改变stu2实例的number字段,再打印结果看看:

    stu2.setNumber(54321);  
      
    System.out.println("学生1:" + stu1.getNumber());  
    System.out.println("学生2:" + stu2.getNumber());  
    

    结果:

    学生1:54321

    学生2:54321

    这就怪了,为什么改变学生2的学号,学生1的学号也发生了变化呢?

    原因出在(stu2 = stu1) 这一句。该语句的作用是将stu1的引用赋值给stu2,

    这样,stu1和stu2指向内存堆中同一个对象。如图:

    2.为什么要克隆

    为什么需要克隆对象呢?直接new一个对象可以吗?

    克隆的对象可能包含一些已经修改过的属性,而new出来的对象的属性都还是初始化时候的值,所以当需要一个新的对象来保存当前的“状态”就靠克隆方法。

    而我们常见的Object a=new Object();Object b;b=a;这种形式的代码复制的是引用,即对象在内存中的地址,a和b对象仍然指向了同一个对象。

    3.如何实现对象克隆

    介绍两种不同的克隆方法:浅克隆和深克隆。

    (1)浅克隆

    • 被复制的类需要实现Clonenable接口(不实现的话在调用clone方法会抛出CloneNotSupportedException异常), 该接口为标记接口(不含任何方法)

    • 覆盖clone()方法,访问修饰符设为public方法中调用super.clone()方法得到需要的复制对象。(native为本地方法)

    下面对上面那个方法进行改造:

    class Student implements Cloneable{  
        private int number;  
      
        public int getNumber() {  
            return number;  
        }  
      
        public void setNumber(int number) {  
            this.number = number;  
        }  
          
        @Override  
        public Object clone() {  
            Student stu = null;  
            try{  
                stu = (Student)super.clone();  
            }catch(CloneNotSupportedException e) {  
                e.printStackTrace();  
            }  
            return stu;  
        }  
    }  
    public class Test {  
        public static void main(String args[]) {  
            Student stu1 = new Student();  
            stu1.setNumber(12345);  
            Student stu2 = (Student)stu1.clone();  
              
            System.out.println("学生1:" + stu1.getNumber());  
            System.out.println("学生2:" + stu2.getNumber());  
              
            stu2.setNumber(54321);  
          
            System.out.println("学生1:" + stu1.getNumber());  
            System.out.println("学生2:" + stu2.getNumber());  
        }  
    }
    

    结果:

    学生1:12345

    学生2:12345

    学生1:12345

    学生2:54321

    上面的复制被称为浅克隆。

    (2)深克隆

    还在学生类里再加一个Address类。

    class Address  {
        private String add;
    
        public String getAdd() {
            return add;
        }
    
        public void setAdd(String add) {
            this.add = add;
        }
    
    }
    
    class Student implements Cloneable{
        private int number;
    
        private Address addr;
    
        public Address getAddr() {
            return addr;
        }
    
        public void setAddr(Address addr) {
            this.addr = addr;
        }
    
        public int getNumber() {
            return number;
        }
    
        public void setNumber(int number) {
            this.number = number;
        }
    
        @Override
        public Object clone() {
            Student stu = null;
            try{
                stu = (Student)super.clone();
            }catch(CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return stu;
        }
    }
    public class Test {
    
        public static void main(String args[]) {
    
            Address addr = new Address();
            addr.setAdd("杭州市");
            Student stu1 = new Student();
            stu1.setNumber(123);
            stu1.setAddr(addr);
    
            Student stu2 = (Student)stu1.clone();
    
            System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
            System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
        }
    }
    

    结果:

    学生1:123,地址:杭州市

    学生2:123,地址:杭州市

    乍一看没什么问题,真的是这样吗?

    我们在main方法中试着改变addr实例的地址。

    addr.setAdd("西湖区");  
      
    System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());  
    System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());  
    

    结果:

    学生1:123,地址:杭州市  
    学生2:123,地址:杭州市  
    学生1:123,地址:西湖区  
    学生2:123,地址:西湖区  
    

    这就奇怪了,怎么两个学生的地址都改变了?

    原因是浅复制只是复制了addr变量的引用,并没有真正的开辟另一块空间,将值复制后再将引用返回给新对象。

    所以,为了达到真正的复制对象,而不是纯粹引用复制。我们需要将Address类可复制化,并且修改clone方法,完整代码如下:

    package abc;
    
    class Address implements Cloneable {
        private String add;
    
        public String getAdd() {
            return add;
        }
    
        public void setAdd(String add) {
            this.add = add;
        }
    
        @Override
        public Object clone() {
            Address addr = null;
            try{
                addr = (Address)super.clone();
            }catch(CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return addr;
        }
    }
    
    class Student implements Cloneable{
        private int number;
    
        private Address addr;
    
        public Address getAddr() {
            return addr;
        }
    
        public void setAddr(Address addr) {
            this.addr = addr;
        }
    
        public int getNumber() {
            return number;
        }
    
        public void setNumber(int number) {
            this.number = number;
        }
    
        @Override
        public Object clone() {
            Student stu = null;
            try{
                stu = (Student)super.clone();   //浅复制
            }catch(CloneNotSupportedException e) {
                e.printStackTrace();
            }
            stu.addr = (Address)addr.clone();   //深度复制
            return stu;
        }
    }
    public class Test {
    
        public static void main(String args[]) {
    
            Address addr = new Address();
            addr.setAdd("杭州市");
            Student stu1 = new Student();
            stu1.setNumber(123);
            stu1.setAddr(addr);
    
            Student stu2 = (Student)stu1.clone();
    
            System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
            System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
    
            addr.setAdd("西湖区");
    
            System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
            System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
        }
    }
    

    结果:

    学生1:123,地址:杭州市  
    学生2:123,地址:杭州市  
    学生1:123,地址:西湖区  
    学生2:123,地址:杭州市  
    

    这样结果就符合我们的想法了。

    (3)浅克隆和深克隆

    浅克隆

    在浅克隆中,如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。

    简单来说,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ARj2RIbL-1607171705687)(D:\software\typora\workplace\imgs_clone\2.png)]

    在Java语言中,通过覆盖Object类的clone()方法可以实现浅克隆

    深克隆

    在深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。

    简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将复制。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zPH7Xndw-1607171705688)(D:\software\typora\workplace\imgs_clone\3.png)]

    在Java语言中,如果需要实现深克隆,可以通过**覆盖Object类的clone()方法实现,也**可以通过序列化(Serialization)等方式来实现。

    Java语言提供的Cloneable接口和Serializable接口的代码非常简单,它们都是空接口,这种空接口也称为标识接口,标识接口中没有任何方法的定义,其作用是告诉JRE这些接口的实现类是否具有某个功能,如是否支持克隆、是否支持序列化等。

    (4)解决多层克隆问题

    如果引用类型里面还包含很多引用类型,或者内层引用类型的类里面又包含引用类型,使用clone方法就会很麻烦。这时我们可以用序列化的方式来实现对象的深克隆。

    Inner也必须实现Serializable,否则无法序列化:

    public class Inner implements Serializable{
      private static final long serialVersionUID = 872390113109L; //最好是显式声明ID
      public String name = "";
    
      public Inner(String name) {
          this.name = name;
      }
    
      @Override
      public String toString() {
          return "Inner的name值为:" + name;
      }
    }
    
    public class Outer implements Serializable{
      private static final long serialVersionUID = 369285298572941L;  //最好是显式声明ID
      public Inner inner;
     //Discription:[深度复制方法,需要对象及对象所有的对象属性都实现序列化]
      public Outer myclone() {
          Outer outer = null;
          try { // 将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝
              ByteArrayOutputStream baos = new ByteArrayOutputStream();
              ObjectOutputStream oos = new ObjectOutputStream(baos);
              oos.writeObject(this);
          // 将流序列化成对象
              ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
              ObjectInputStream ois = new ObjectInputStream(bais);
              outer = (Outer) ois.readObject();
          } catch (IOException e) {
              e.printStackTrace();
          } catch (ClassNotFoundException e) {
              e.printStackTrace();
          }
          return outer;
      }
    }
    
    展开全文
  • 对象克隆

    2021-07-21 16:24:09
    为什么需要对象克隆?直接new一个对象不行吗? 克隆对象可能包含一些已经修改过的属性,而new出来的对象的属性都还是...这种形式的代码复制实际上只是引用,b复制了a在内存中的地址,a和b指向了同一个对象。所以这种

    为什么需要对象克隆?直接new一个对象不行吗?

    克隆的对象可能包含一些已经修改过的属性,而new出来的对象的属性都还是初始化时候的值,所以当需要一个新的对象来保存当前对象的“状态”就靠clone方法了。相比把临时属性一个个赋给new出来的对象,clone是一个native方法吧,在底层实现,更方便,速度更快。

    误区:

    我们常见的:

    Student a = new Student();
    Student b = a;
    

    这种形式的代码复制实际上只是引用,b复制了a在内存中的地址,a和b指向了同一个对象。所以这种只能称为引用复制,两个引用指向的还是同一个对象。

    image-20210721145114091

    如何实现克隆

    先介绍一下两种不同的克隆方法,浅克隆深克隆

    在Java中,数据类型分为值类型(基本数据类型)和引用类型,值类型包括int、double、byte、boolean、char、float、short、long八种简单数据类型,引用类型包括类、接口和数组复杂类型。基本数据类型的值可以直接复制,引用类型只能复制引用地址。所以浅克隆和深克隆的主要区别在于是否支持引用类型的成员变量的复制。

    浅克隆和深克隆

    1.浅克隆

    在浅克隆中如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。

    简单地说,在浅克隆中,当对象被复制时只复制自身和其中包含值类型的成员变量,而引用类型的成员对象并没有复制。

    image-20210721155157274

    在Java语言中,通过覆盖Object类的clone()方法可以实现浅克隆。

    2.深克隆

    在深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。

    简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将被复制。

    在Java语言中,如果需要实现深克隆,可以通过覆盖Object类的clone()方法实现,也可以通过序列化等方式来实现。

    序列化就是将对象写到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象任然存在于内存中。通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象,因此通过序列化将对象写到一个流中,再从流中将其读出来,可以实现深克隆。需要注意的是能够实现序列化的对象其类必须实现Seralizable接口,否则无法实现序列化操作。

    image-20210721162114774

    解决多次克隆问题

    如果引用类型里面还包含很多引用类型,或者内层引用类型的类里面又包含引用类型,使用clone方法就会很麻烦。这时可以用序列化的方式来实现对象的深克隆。

    展开全文
  • 参考我的文章http://blog.csdn.net/ideality_hunter/article/details/72725931... 那是有个例外,String,其不是java的基本数据类型。而是和Integer一样的扩展类即Class。 String a="a"; String b=a;...System.out.prin

    参考我的文章http://blog.csdn.net/ideality_hunter/article/details/72725931



    那是有个例外,String,其不是java的基本数据类型。而是和Integer一样的扩展类即Class。

    String a="a";

    String b=a;

    System.out.println(a);

    System.out.println(b);

    String b="b";

    System.out.println(a);

    System.out.println(b);


    这是为什么?




    展开全文
  • 对象克隆复制工具

    2018-07-31 16:25:37
    对象复制工具,基于cglib BeanCopier 实现对实体对象、持久化对象、代理对象的克隆和复制, 避免重复克隆和复制,避免无限循环引用,(校验hashCode) 可指定实体对象和集合属性的克隆深度
  • java对象复制克隆

    2013-10-28 08:52:09
    深度复制Java对象实例,复制对象属性值改变不影响被复制对象,有注释
  • 主要介绍了Java编程实现对象克隆复制)代码详解,涉及了克隆的原因,如何实现克隆克隆的一般步骤,深克隆与浅克隆的介绍等相关内容,具有一定借鉴价值,需要的朋友可以参考下。
  • Java对象克隆

    2017-11-10 22:50:46
    Java对象克隆Java对象克隆,也叫对象复制,对象拷贝。 为什么会有这个操作呢?试想有一个实体类,有很多属性,并且很多属性已经赋了值,这个时候需要对这个对象进行修改操作,但后面还会用到原来的值。赋值如果只是...

    Java对象克隆

    Java对象克隆,也叫对象复制,对象拷贝。
    为什么会有这个操作呢?试想有一个实体类,有很多属性,并且很多属性已经赋了值,这个时候需要对这个对象进行修改操作,但后面还会用到原来的值。

    赋值

    如果只是简单的声明new一个对象,使用赋值操作把旧对象赋给新对象,当对新对象修改时,旧对象的值同样会变,因为新对象只是指向旧对象的一个引用。

    浅克隆

    被克隆的类实现Cloneable接口,重写clone方法。这种克隆方式,如果被克隆的类中成员变量都是基本数据类型,可以实现了两份数据。吐过被克隆的类中成员变量包含对象类型的成员变量,那么这个成员变量还是原来的引用,修改新对象的值,旧对象的该对象类型的成员变量还是会变化。即浅克隆。

    深克隆

    被克隆的类以及它的对象类型的成员变量都实现了Cloneable接口,重写了clone方法。即深克隆。

    使用序列化辅助克隆

    待续

    展开全文
  • 对象克隆复制)假如说你想复制一个简单变量。很简单:int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short,float,double.long)同样适用于该类情况。但是如果你...
  • 实现对象克隆有两种方式:   1). 实现Cloneable接口并重写Object类中的clone()方法;   2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆
  • 对象克隆知识点

    2021-08-06 14:36:39
    对象克隆知识点 1.对象克隆 ​ 将原有的一个包含数据的对象克隆出一个新的对象,新对象包含原来对象数据。 2为什么需要克隆? ​ 克隆对象可能包含一些已经修改过的属性,而new出来的对象的属性都还是初始化时候...
  • java对象克隆

    2015-10-12 00:13:44
    对象克隆对象复制,完整的复制一个对象 clone()方法是定义在java.lang.Object类中,如下: protected Object clone() throws CloneNotSupportedException 该方法是一个protected的方法,所以重载时要把clone()...
  • 主要介绍了php实现对象克隆的方法,实例分析了php对象实例化与克隆的使用技巧,需要的朋友可以参考下
  • 主要介绍了PHP对象克隆clone用法,结合实例形式分析了php浅克隆与深克隆的相关概念、特点与实现方法,需要的朋友可以参考下
  • Java进阶之对象克隆复制

    千次阅读 2018-09-23 11:18:59
    转载自 Java进阶之对象克隆复制) 假如说你想复制一个简单变量。很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short,float,double.long)同样...
  • https://www.cnblogs.com/showcase/p/10489636.html
  • 1.对象克隆 clone PHP4面向对象功能一个很大的缺点,是将对象视为另一种数据类型,这使得很多常见的OOP方法无法使用,如设计模式。这些方法依赖于将对象作为引用传递给其他类方法,而不是作为值传递,而按值传递却是...
  • 如何实现对象克隆

    千次阅读 多人点赞 2019-06-18 14:23:54
    如何实现对象克隆? 实现 Cloneable 接口,重写 clone() 方法。 不实现 Cloneable 接口,会报 CloneNotSupportedException 异常。 package constxiong.interview; /** * 测试克隆 * @author ConstXiong * @...
  • 当你想把对象的某一个属性更改后再添加到一个列表的时候,就会被最后的对象替换掉,就不能实现新对象的添加。下面两种方式可以实现对象赋值给同类型的对象,这两个对象的堆栈信息是不一样的。 方法一: 必须对对象...
  • 对象克隆 关于java克隆,感谢这位博主的总结,相当到位:http://www.cnblogs.com/Qian123/p/5710533.html#commentform 对象克隆需要在该对象的类中实现Cloneable这个标记接口(类似的标记接口有Serializable,...
  • 理解java中的对象克隆

    2020-05-24 18:05:10
    所谓的对象克隆描述的概念就是进行对象复制,当一个对象完成之后实际上都会自动的开辟内存空间,在每一块堆内存空间里面都会保存有对象的相关属性内容,所谓的对象克隆它描述的就是属性的复制。 如果想要完成对象...
  • Delphi对象克隆技术

    千次阅读 2018-04-26 11:24:56
    Delphi交流QQ:2609715119关键字: 原型模式,对象克隆,Prototype,Clone概述:在这...本文还探讨了对象引用复制对象克隆的区别,以及VCL的持久对象机制、对象流化技术。1、原型模式解说原型模式通过给出一个原型对象...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,098,106
精华内容 439,242
关键字:

对象复制