深入学习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 TypeMethod and Description
protected Objectclone()

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

booleanequals(Object obj)

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

protected voidfinalize()

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

<?>getClass()

返回此 Object的运行时类。

inthashCode()

返回对象的哈希码值。

voidnotify()

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

voidnotifyAll()

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

StringtoString()

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

voidwait()

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

voidwait(long timeout)

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

voidwait(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 { }
}

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wespten

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值