深入学习java源码之Object.clone()与Object.notifyAll()

深入学习java源码之Object.clone()与Object.notifyAll()

super.clone()

最早使用clone方法的是object类,这个类是所有类的父类,在重写方法时调用父类方法肯定用super了,this是本身,但子类本身没有clone方法,是从父类object继承的。

Object中的clone执行的时候使用了RTTI(run-time type identification)的机制,动态得找到目前正在调用clone方法的那个reference,根据它的大小申请内存空间,然后进行bitwise的复制,将该对象的内存空间完全复制到新的空间中去,从而达到shallowcopy的目的。
所以调用super.clone() 得到的是当前调用类的副本,而不是父类的副本。

要让实例调用clone方法就需要让此类实现Cloneable接口,API里面还有句话是:如果在没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException 异常,这便是“合法”的含义。 但请注意,Cloneable接口只是个标签接口,不含任何需要实现的方法,就像Serializable接口一样。

总之,一般如果子类没有特殊需要而重写clone()方法就直接用super.clone() 就行了。

 

浅拷贝与深拷贝

浅拷贝,就是Object默认的clone方法,完全的copy了这个类,基本数据类型copy了值,引用数据类型copy的是对象的引用,所以如果要对对象进行修改,可以使用深拷贝。 所谓的深拷贝,就是自己重写了一下clone方法,将引用变量变成值传递而不是引用传递。

浅克隆(shadow clone)

   克隆就是复制一个对象的复本.若只需要复制对象的字段值(对于基本数据类型,如:int,long,float等,则复制值;对于复合数据类型仅复制该字段值,如数组变量则复制地址,对于对象变量则复制对象的reference。

class Person implements Cloneable{
    @Override
    protected Person clone() throws CloneNotSupportedException {
        return (Person) super.clone();
    }

    String name;
    int age;
    Job job;
    @Override
    public String toString(){
        return "name: " + name + ",age: " + age + ",job:  " + job;
    }
}
class Job{
    String jobName;
    String address;
}
public class CloneTest {
    @Test
    public void shaowClone() throws Exception{
        Person p1 = new Person();
        p1.setName("guo");
        p1.setAge(22);
        Job job = new Job();
        job.setJobName("IT");
        job.setAddress("shanghai");
        p1.setJob(job);

        Person p2 = p1.clone();
        System.out.println(p1.toString());
        System.out.println(p2.toString());

        p2.getJob().setJobName("programmer");
        System.out.println(p1.getJob().getJobName());
    }

  得到结果:
    name: guo,age: 22,job: test.Job@4f2410ac
    name: guo,age: 22,job: test.Job@4f2410ac
    programmer

clone方法就是返回一个原对象的拷贝,默认走的是浅拷贝。克隆的目的是复制对象,但是新的对象是独立于原来的对象的,一般我们克隆出来的对象都在一些属性做了更改,这个时候需要小心一点,如果更改的属性是引用数据类型,可能会影响到原来的对象,如果都是基本数据类型则不怕。使用clone方法的前提是继承Cloneable接口,数组默认实现了Cloneable接口,默认走的是浅拷贝。

public class ShadowClone implements Cloneable{  
         
    private int a;   // 基本类型  
    private int[] b; // 非基本类型  
    // 重写Object.clone()方法,并把protected改为public  
    @Override  
    public Object clone(){  
        ShadowClone sc = null;  
        try  
        {  
            sc = (ShadowClone) super.clone();  
        } catch (CloneNotSupportedException e){  
            e.printStackTrace();  
        }  
        return sc;  
    }  
    public int getA()  
    {  
        return a;  
    }  
    public void setA(int a)  
    {  
        this.a = a;  
    }  
    public int[] getB() {  
    return b;  
    }  
    public void setB(int[] b) {  
    this.b = b;  
    }    
}  


ShadowClone c1 = new ShadowClone();  
//对c1赋值  
c1.setA(100) ;  
c1.setB(new int[]{1000}) ;  
System.out.println("克隆前c1:  a="+c1.getA()+" b="+c1.getB()[0]);  
//克隆出对象c2,并对c2的属性A,B,C进行修改  
ShadowClone c2 = (ShadowClone) c1.clone();  
//对c2进行修改  
c2.setA(50) ;  
int []a = c2.getB() ;  
a[0]=5 ;  
c2.setB(a);  
System.out.println("克隆前c1:  a="+c1.getA()+" b="+c1.getB()[0]);  
System.out.println("克隆后c2:  a="+c2.getA()+ " b[0]="+c2.getB()[0]);  


克隆前c1:  a=100 b=1000
克隆前c1:  a=100 b=5
克隆后c2:  a=50 b[0]=5

基本类型可以使用浅克隆,而对于引用类型,由于引用的是内容相同,所以改变c2实例对象中的属性就会影响到c1。所以引用类型需要使用深克隆。另外,在开发一个不可变类的时候,如果这个不可变类中成员有引用类型,则就需要通过深克隆来达到不可变的目的。

深克隆(deep clone)

    深克隆与浅克隆的区别在于对复合数据类型的复制。若对象中的某个字段为复合类型,在克隆对象的时候,需要为该字段重新创建一个对象。

就是自己重写了一下clone方法,将引用变量变成值传递而不是引用传递

public class DeepClone implements Cloneable {  
  
    private int a;   // 基本类型  
    private int[] b; // 非基本类型  
    // 重写Object.clone()方法,并把protected改为public  
    @Override  
    public Object clone(){  
        DeepClone sc = null;  
        try  
        {  
            sc = (DeepClone) super.clone();  
            int[] t = sc.getB();  
            int[] b1 = new int[t.length];  
            for (int i = 0; i < b1.length; i++) {  
                b1[i] = t[i];  
            }  
            sc.setB(b1);  
        } catch (CloneNotSupportedException e){  
            e.printStackTrace();  
        }  
        return sc;  
    }  
    public int getA()  
    {  
        return a;  
    }  
    public void setA(int a)  
    {  
        this.a = a;  
    }  
    public int[] getB() {  
        return b;  
    }  
    public void setB(int[] b) {  
        this.b = b;  
    }  
}  

 

Class Object是类Object结构的根。 每个班都有Object作为超类。 所有对象(包括数组)都实现了这个类的方法。

Modifier and Type Method and Description
protected Object clone()

创建并返回此对象的副本。

boolean equals(Object obj)

指示一些其他对象是否等于此。

protected void finalize()

当垃圾收集确定不再有对该对象的引用时,垃圾收集器在对象上调用该对象。

getClass()

返回此 Object的运行时类。

int hashCode()

返回对象的哈希码值。

void notify()

唤醒正在等待对象监视器的单个线程。

void notifyAll()

唤醒正在等待对象监视器的所有线程。

String toString()

返回对象的字符串表示形式。

void wait()

导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法。

void wait(long timeout)

导致当前线程等待,直到另一个线程调用 notify()方法或该对象的 notifyAll()方法,或者指定的时间已过。

void wait(long timeout, int nanos)

导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法,或者某些其他线程中断当前线程,或一定量的实时时间。

java源码

package java.lang;

public class Object {

    private static native void registerNatives();
    static {
        registerNatives();
    }

    public final native Class getClass();

    public native int hashCode();

    public boolean equals(Object obj) {
        return (this == obj);
    }	
	
    protected native Object clone() throws CloneNotSupportedException;	
	
    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }	
	
    public final native void notify();	
	
    public final native void notifyAll();	
	
    public final native void wait(long timeout) throws InterruptedException;	

    public final void wait(long timeout, int nanos) throws InterruptedException {
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos > 0) {
            timeout++;
        }

        wait(timeout);
    }

    public final void wait() throws InterruptedException {
        wait(0);
    }
	
    protected void finalize() throws Throwable { }
}

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(Java源码)