package com.blb.考前;
public class Person implements Cloneable {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
@Override
public Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
}
package com.blb.考前;
public class Demo01 {
public static void main(String[] args) throws CloneNotSupportedException {
// TODO Auto-generated method stub
Person person = new Person();
person.setAge(11);
person.setName("张三");
System.out.println(person);
Person person2 = (Person) person.clone();
System.out.println(person2);
System.out.println(person.hashCode());
System.out.println(person2.hashCode());
System.out.println(person.getAge()==person2.getAge());
}
}
话不多说,这个就是前克隆的代码。首先我们先看看什么是克隆?
这个是最开始的类中的clone方法,注意在Object类中这个方法被native修饰,那么什么情况下这个会被native修饰呢?
native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中。Java语言本身不能对操作系统底层进行访问和操作,但是可以通过JNI接口调用其他语言来实现对底层的访问。所以说这个方法可以实现java对底层的访问的。这个对于我们理解下面的克隆方法就很关键。
大家看我上面的代码会发现,一个类要实现克隆即必须要实现Cloneable接口,因为我们也可以看到本地的克隆方法是无法被你直接调用的,这个时候我们就需要继承或者实现某个接口,在这里我们就是要实现Cloneable这个接口。
可以看到这个接口里没有抽象方法,我们要实现这个克隆方法就必须重写它。
在重写完以后我们最好还是要将这个默认的projected改为public。然后我们可以来看看运行结果,在欠克隆的情况下。
我们可以看到克隆出来的对象跟对象本身的表现形式是完全一样的!但是它们的hashcode值不一样,所以我们可以得到两个对象的内存地址一定不相同。所以在堆内存中这一定是两个完全不同的对象。但是奇怪的是 System.out.println(person.getAge()==person2.getAge());返回的结果却是true说明对象的属性的内存地址确是相同的,说明在方法区中这个两个对象的属性引用的一块内存,这个就是浅克隆,虽然是两个完全不同的对象,用的却是同一块内存上的东西。
而深克隆的就是真正意义上克隆处两份完全不同的对象。两个对象的地址不同,所引用的属性地址也不相同。这个就是深克隆。(至于深克隆的实现,要自己重写clone方法,我现在还是个小菜鸡,有大佬可以评论区聊聊。)