类实现Cloneable接口,重写clone方法、方法内容默认调用父类的clone方法。
-
浅拷贝
- 基础类型的变量拷贝之后是独立的,不会随着源变量变动而变
- String类型拷贝之后也是独立的(final)
- 引用类型拷贝的是引用地址,拷贝前后的变量引用同一个堆中的对象
- 深拷贝
- 变量的所有引用类型变量(除了String)都需要实现Cloneable(数组可以直接调用clone方法),clone方法中,引用类型需要各
- 自调用clone,重新赋值
static void cloneTest() throws CloneNotSupportedException {
Student student = new Student(1, "张", 10, new School(1, "清华"));
System.out.println(student);
Student clone = student.clone();
clone.setId(2);
clone.setName("li");
clone.setAge(18);
clone.getSchool().id = 2;
clone.getSchool().name = "beida";
System.out.println("clone---->" + clone);
System.out.println("student-->" + student);
}
@AllArgsConstructor
@Data
static class Student implements Cloneable {
int id;
String name;
Integer age;
School school;
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", school=" + school +
'}';
}
@Override
public Student clone() throws CloneNotSupportedException {
Student clone = (Student) super.clone(); // 只拷贝基本类型
// clone.school = clone.getSchool().clone(); // 拷贝引用类型
return clone;
}
}
@AllArgsConstructor
static class School implements Cloneable {
int id;
String name;
@Override
public String toString() {
return "School{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
@Override
public School clone() throws CloneNotSupportedException {
return (School) super.clone();
}
}
如果注释掉这段代码,
// clone.school = clone.getSchool().clone(); // 拷贝引用类型
输出之后可以发现,基础类型的原值没有改动,但是引用类型的school被改了,这就是浅拷贝。
那么如果取消注释呢?可以看到都没有变化,这就是深拷贝,修改拷贝对象,对原来的对象所有属性都没有影响
java的传参,基本类型和引用类型传参
java在方法传递参数时,是将变量复制一份,然后传入方法体去执行。复制的是栈中的内容
所以基本类型是复制的变量名和值,值变了不影响源变量
引用类型复制的是变量名和值(引用地址),对象变了,会影响源变量(引用地址是一样的)
String:是不可变对象,重新赋值时,会在常量表新生成字符串(如果已有,直接取他的引用地址),将新字符串的引用地址赋值给栈中的新变量,因此源变量不会受影响