Java中的Clone

Java Clone

1.克隆的概念
    A:
浅复制(浅克隆): 浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。 

   注:Object类里的clone方法是浅复制(浅克隆)
    B:
深复制(深克隆):深复制把要复制的对象所引用的对象都复制了一遍。 

   C: Clone的公约
        1. x.clone() != x // x.clone() will return a new object

        2. x.clone().equals(x) // this is the meaning of ‘copy’

        3. x.clone().getClass() == x.getClass() 


        4. The object returned by clone method should be independent of the object (which is  
            being cloned).

 

 

 

      These are not absolute requirements but are general intends of clone method which is also recommended in Java

        Documents.

2.对象克隆的两种方式
A.我们可以利用Object类的clone()方法,必须要遵循下面三点 
     (1)
在派生类中覆盖基类的clone()方法,并声明为public Object类中的clone()方法为protected的】。 
     (2)
在派生类的clone()方法中,调用super.clone() 
     (3)
在派生类中实现Cloneable接口。

     被克隆的类必须自己实现Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。Cloneable 接口实际上是个标识接口,没有任何接口方法。实现Cloneable接口的类应该使用公共方法重写 Object.clone(它是受保护的)。某个对象实现了此接口就克隆它是不可能的。即使 clone 方法是反射性调用的,也无法保证它将获得成功。在Java.lang.Object类中克隆方法是这么定义的:

protected Object clone()  throws CloneNotSupportedException

创建并返回此对象的一个副本。表明是一个受保护的方法,同一个包中可见。按照惯例,返回的对象应该通过调用 super.clone 获得。

如果没有实现Cloneable 接口,调用clone()方法时会抛出CloneNotSupportedException异常。

a. Class A成员变量类型是java的基本类型时(外加String类型,因为在javaString被写成了一个不可更改的类(immutable class),在所有String类中的函数都不能更改自身的值,每次对String的操作都是生成新的对象,而这些操作如果没有赋值就不存在任何意义)

public class A implements Cloneable {  
    public String name;  
  
    public Object clone() {  
        A o = null;  
        try {  
            o = (A) super.clone();  
        } catch (CloneNotSupportedException e) {  
            e.printStackTrace();  
        }  
        return o;  
    }  
  
}  

 

 

 

b. ClassA成员变量类型是对象时(包括数组(基本类型数组,数组自实现了clone方法),集合(基本类型集合))

 

public class B implements Cloneable {
public String name; 

public Object clone() {  
        B o = null;  
        try {  
            o = (B) super.clone(); //当然Class B也要实现相应clone方法  
        } catch (CloneNotSupportedException e) {  
            e.printStackTrace();  
        }  
        return o;  
    }  
}

public class A implements Cloneable { 
        public String name; 
        public String[] group = new String[2]; 
        public B b;

        public Object clone() { 
              A o = null; 
              try { 
                   o = (A) super.clone(); 
                   o.group = (String[])group.clone(); 
                   o.b = (B)b.clone();
              } catch (CloneNotSupportedException e) { 
                      e.printStackTrace(); 
              } 
              return o; 
        }
}

 

c. Class A存在更为复杂的成员变量时,如非基本类型数组和非基本类型集合时。

 

 

public class B implements Cloneable {
     public String name; 

     public Object clone() {  
         B o = null;  
         try {  
               o = (B) super.clone();  
       } catch (CloneNotSupportedException e) {  
           e.printStackTrace();  
         }  
      return o;  
     }  
}

public class A implements Cloneable {  
    public String name[];  
    public Vector<B> claB;  
      
    public A(){  
        name=new String[2];  
        claB=new Vector<B>();  
    }  
  
    public Object clone() {  
        A o = null;  
        try {  
            o = (A) super.clone();  
            o.name==(String[])name.clone();//深度clone  
            o.claB=new Vector<B>();//将clone进行到底  
            for(int i=0;i<claB.size();i++){  
                B temp=(B)claB.get(i).clone();//当然Class B也要实现相应clone方法  
                o.claB.add(temp);  
            }  
        } catch (CloneNotSupportedException e) {  
            e.printStackTrace();  
        }  
                return o;  
    }  
}  

 

关于数组集合,数组的话就克隆了数组的引用,集合的话就集合容器而已,其中的元素未克隆,说的好像不太清楚,心里懂但是说不清楚真是着急。

总结一下其实克隆每次只克隆对象本身(基本类型),引用类型只克隆引用,不会克隆引用的内容。

 

B. 利用序列化来做深复制,把对象写到流里的过程是序列化(Serilization)过程,而把对象从流中读出来的过程则叫做反序列化(Deserialization)过程。应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。,利用这个特性,可以做深拷贝。

 

public class A implements Cloneable, Serializable {
public String name;

public Object deepCopy() throws IOException {
    Object obj = null;
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(bos);
    oos.writeObject(this);
    ByteArrayInputStream bis = new ByteArrayInputStream (bos.toByteArray());
    ObjectInputStream ois = new ObjectInputStream(bis);
    obj = ois.readObject();
    return obj;
}

 

### Java 中对象克隆时深复制和浅复制的区别 在 Java 中,当一个对象实现了 `Cloneable` 接口并调用了 `clone()` 方法来创建副本时,可以区分两种类型的复制行为:浅复制和深复制。 #### 浅复制 浅复制是指新对象会被创建,但是该对象中的成员变量只会简单地复制其引用而不是实际的对象实例。这意味着原始对象及其副本将共享相同的内部对象状态。如果其中一个对象修改了这些共享的状态,则另一个也会受到影响[^1]。 对于基本数据类型(如 int、boolean),它们会在浅复制过程中被完全独立地复制;而对于复杂的数据结构(比如数组或其他对象),则只是复制了指向这些对象的引用地址而非真正的内容[^2]。 ```java public class ShallowCopyExample implements Cloneable { private String name; private Address address; @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } } ``` #### 深复制 相比之下,在执行深复制操作时,不仅会创建一个新的目标对象,还会递归地为源对象内的每一个可变字段都分配新的内存空间,并把相应的内容完整地复制过去。因此,两个对象之间没有任何关联关系,各自拥有自己的一份独立数据副本[^3]。 为了实现深复制,通常有两种常见的方式: - **手动编写自定义的 `clone()` 方法**:在这个方法里显式地对每个需要深层复制的属性进行处理。 ```java public class DeepCopyExample implements Cloneable { private String name; private Address address; @Override public DeepCopyExample clone() throws CloneNotSupportedException { DeepCopyExample copy = (DeepCopyExample)super.clone(); // 手动复制Address对象 if(this.address != null){ copy.address = this.address.clone(); }else{ copy.address=null; } return copy; } } class Address implements Cloneable { private String city; @Override public Address clone() throws CloneNotSupportedException { return (Address)super.clone(); } } ``` - **利用序列化机制**:这种方式不需要开发者额外编码即可完成整个对象图谱的深度复制过程。不过这种方法依赖于所有涉及类均支持序列化的前提条件。 ```java import java.io.*; public class SerializationDeepCopy<T extends Serializable> { public static <T extends Serializable> T deepCopy(T obj) throws IOException, ClassNotFoundException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(bos); out.writeObject(obj); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream in = new ObjectInputStream(bis); return (T)in.readObject(); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值