偶然看到clone()方法,发现我对这个方法如此陌生,还是Object里的方法,不去了解怎么行
了解的最好办法就是直接去看源码了,发现是个native方法,去看注释
/**
* Creates and returns a copy of this object. The precise meaning
* of "copy" may depend on the class of the object. The general
* intent is that, for any object {@code x}, the expression:
·········
* By convention, the object returned by this method should be independent
* of this object (which is being cloned). To achieve this independence,
* it may be necessary to modify one or more fields of the object returned
* by {@code super.clone} before returning it. Typically, this means
* copying any mutable objects that comprise the internal "deep structure"
* of the object being cloned and replacing the references to these
* objects with references to the copies. If a class contains only
* primitive fields or references to immutable objects, then it is usually
* the case that no fields in the object returned by {@code super.clone}
* need to be modified.
* <p>
* The method {@code clone} for class {@code Object} performs a
* specific cloning operation. First, if the class of this object does
* not implement the interface {@code Cloneable}, then a
* {@code CloneNotSupportedException} is thrown. Note that all arrays
* are considered to implement the interface {@code Cloneable} and that
* the return type of the {@code clone} method of an array type {@code T[]}
* is {@code T[]} where T is any reference or primitive type.
* Otherwise, this method creates a new instance of the class of this
* object and initializes all its fields with exactly the contents of
* the corresponding fields of this object, as if by assignment; the
* contents of the fields are not themselves cloned. Thus, this method
* performs a "shallow copy" of this object, not a "deep copy" operation.
* <p>
* The class {@code Object} does not itself implement the interface
* {@code Cloneable}, so calling the {@code clone} method on an object
* whose class is {@code Object} will result in throwing an
* exception at run time.
*
*/
只摘录了重要的一部分
开头一段话意思是:
创建并返回此对象的副本。 “复制”的确切含义可能取决于对象的类别。一般意图是,对于任何对象{@code x},表达式为:x.clone() != x
也就是说,确实是一个新的对象,去实验下:
新建了个Student里面
public class Student implements Cloneable{
private String name;
private int age;
public Person(String name, int age, Adress adress){
this.name = name;
this.age = 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
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", adress=" + adress.toString() +
'}';
}
}
Student s1 = new Student(“abc”, 13);
Student s2 = s1.clone();
System.out.println(s1 == s2);
输出为false, emmm。。。。好像是这么回事
那接着来看下面的注释
* x.clone() != x</pre></blockquote>
* will be true, and that the expression:
* <blockquote>
* <pre>
* x.clone().getClass() == x.getClass()</pre></blockquote>
* will be {@code true}, but these are not absolute requirements.
* While it is typically the case that:
* <blockquote>
* <pre>
* x.clone().equals(x)</pre></blockquote>
* will be {@code true}, this is not an absolute requirement.
* <p>
x.clone() !- x 也就是说不是同一对象,x.clone().geClass() == x.getClass() 为true说明是同一类型,这不肯定的嘛
x.clone().equals(x)也一样的
那接着看你下面的
By convention, the object returned by this method should be independent
* of this object (which is being cloned). To achieve this independence,
* it may be necessary to modify one or more fields of the object returned
* by {@code super.clone} before returning it. Typically, this means
* copying any mutable objects that comprise the internal "deep structure"
* of the object being cloned and replacing the references to these
* objects with references to the copies. If a class contains only
* primitive fields or references to immutable objects, then it is usually
* the case that no fields in the object returned by {@code super.clone}
* need to be modified.
* <p>
这段话的意思是clone()按照字面意思是应该返回一个独立于被复制对象的新对象,但是该方法是通过赋值来进行复制的,所以对于引用对象,便会指向被复制对象的地址,所以,对于引用对象这种含有深层结构的类型,在其内部也都需要clone()。但是基本类型则不需要。
举个例子,在上面的Student类中。新加个Home
public class Home{
public String name;
public String code;
public Home(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Override
public String toString() {
return "Home{" +
"name='" + name + '\'' +
", code='" + code + '\'' +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
先试下
public class Student implements Cloneable{
private String name;
private int age;
private Home home;
public Person(String name, int age, Home home){
this.name = name;
this.age = 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;
}
public int getHome() {
return home;
}
public void setHome(Home home) {
this.home= home;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", adress=" + home.toString() +
'}';
}
}
Home home = new Home();
home.setName("aaaa");
home.setCode("001");
Student s1 = new Student("张三", 13, home);
Student s2 = s1.clone();
System.out.println(s1 == s2);
输出是false,没什么问题,那我们来改一下
Home home = new Home();
home.setName("aaaa");
home.setCode("001");
Student s1 = new Student("张三", 13, home);
Student s2 = s1.clone();
System.out.println(s1 == s2);
System.out.println(s1.toString() +"---"+ s2.toString());
s2.getHome().setName("bbb");
System.out.println(s1 == s2);
System.out.println(s1.toString() +"---"+ s2.toString());
s1 == s2都是false,但是第二次s1.toString()输出的值发生了改变,其中home里的name = “bbb”
印证了上面所说的对于引用类型的描述
所以,需要进行深层的clone(),对Student类的clone()重写一下
@Override
protected Object clone() throws CloneNotSupportedException {
Student st= (Student) super.clone();
st.setAdress((Adress) st.getAdress().clone());
return st;
}
再次运行,便不会出现同时改变的情况了
false
Student{name=‘张三’, age=13, home=Home{name=‘bbb’, code=‘001’}}—Student{name=‘张三’, age=13, home=Home{name=‘bbb’, code=‘001’}}
false
Student{name=‘张三’, age=13, home=Home{name=‘aaaa’, code=‘001’}}—Student{name=‘张三’, age=13, home=Home{name=‘bbb’, code=‘001’}}
接下来看下一段话
* The method {@code clone} for class {@code Object} performs a
* specific cloning operation. First, if the class of this object does
* not implement the interface {@code Cloneable}, then a
* {@code CloneNotSupportedException} is thrown. Note that all arrays
* are considered to implement the interface {@code Cloneable} and that
* the return type of the {@code clone} method of an array type {@code T[]}
* is {@code T[]} where T is any reference or primitive type.
* Otherwise, this method creates a new instance of the class of this
* object and initializes all its fields with exactly the contents of
* the corresponding fields of this object, as if by assignment; the
* contents of the fields are not themselves cloned. Thus, this method
* performs a "shallow copy" of this object, not a "deep copy" operation.
* <p>
* The class {@code Object} does not itself implement the interface
* {@code Cloneable}, so calling the {@code clone} method on an object
* whose class is {@code Object} will result in throwing an
* exception at run time.
如果此对象的类未实现接口 Cloneable,则抛出 CloneNotSupportedException异常,而且**注意:**数组是默认实现该方法的,而且复制后的数组与原数组是独立的,也就是说clone()后的数组改变里面的值不会影响到原数组,也就是深拷贝。
来了解下深拷贝,浅拷贝的含义:
- 浅拷贝:被复制对象的所有值属性都含有与原来对象的相同,但是所有的对象引用属性仍然指向原来的对象。
- 深拷贝:在浅拷贝的基础上,所有引用其他对象的变量也进行了clone,并指向被复制过的新对象。
也就是说浅拷贝对于引用对象只是简单的指向被复制对象指向的地址,深拷贝则会是指向新赋值的地址。