背景
Java中想要复制对象时,需要考虑到一个问题:如果是引用类型对象,如果只是通过一般的“=”赋值,那么因为只是把引用地址给了新对象,所以改变新对象时会因为实际改变的引用地址指向的对象,因此难免出现改变源对象的属性。例如:
public class Demo1 {
static class People {
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}
public static void main(String[] args) {
People people1 = new People();
people1.setName("zhangsan");
people1.setAge("23");
System.out.println("源对象:" + people1);
People people2 = people1;
System.out.println("新对象:" + people2);
people2.setName("lisi");
System.out.println("修改后的源对象:" + people1);
System.out.println("修改后的新对象:" + people2);
}
}
结果:
源对象:People{name='zhangsan', age='23'}
新对象:People{name='zhangsan', age='23'}
修改后的源对象:People{name='lisi', age='23'}
修改后的新对象:People{name='lisi', age='23'}
因此这时就需要考虑解决办法,如何把源对象的属性给新对象,而且两个对象改变属性时又可以不相互影响?
概念
Java复制对象的实现方式中有个“克隆”的概念,就是复制一个对象的副本,而克隆又分浅克隆和深克隆。
- 浅克隆:克隆一个新对象,但是属性如果是引用类型对象则用的同一个引动地址指向的对象。
- 深克隆:克隆一个新对象,包括引用类型的属性内存地址指向的也是新创建的对象。
实现步骤:
- 实现Clonable接口;
- 重写clone()方法。
- 调用clone()方法克隆对象。
浅克隆
1、验证是否为新对象
bean(未重写toString(),用来验证克隆出的对象是否为新的)
public class People 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;
}
//修改权限为:public
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
main
public static void main(String[] args) throws CloneNotSupportedException {
People old = new People();
old.setName("zhangsan");
old.setAge(23);
People clone = (People) old.clone();
System.out.println("源对象:" + old);
System.out.println("新对象:" + clone);
}
结果:地址不同,所以clone的新对象和原来的不是同一个
源对象:com.company.bean.People@4554617c
新对象:com.company.bean.People@74a14482
2、验证引用类型属性是否为新的
Car
public class Car implements Cloneable {
private String name;
private String color;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
People
public class People implements Cloneable {
private String name;
private int age;
private Car car;
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 Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
//修改权限为:public
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", age=" + age +
", car=" + car +
'}';
}
}
main
public static void main(String[] args) throws CloneNotSupportedException {
People old = new People();
old.setName("zhangsan");
old.setAge(23);
Car car = new Car();
car.setName("ferrari");
car.setColor("red");
old.setCar(car);
People clone = (People) old.clone();
System.out.println("源对象:" + old);
System.out.println("新对象:" + clone);
}
结果:虽然对象是新的,但是clone的属性还是用一个。
源对象:People{name='zhangsan', age=23, car=com.company.bean.Car@4554617c}
新对象:People{name='zhangsan', age=23, car=com.company.bean.Car@4554617c}
深克隆:重写对象中引用类型属性clone()
Car
public class Car implements Cloneable {
private String name;
private String color;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
//重写clone
@Override
public Car clone() throws CloneNotSupportedException {
return (Car) super.clone();
}
}
People
public class People implements Cloneable {
private String name;
private int age;
private Car car;
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 Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
//重写clone方法
@Override
public People clone() throws CloneNotSupportedException {
People people = (People) super.clone();
people.car = car.clone();
return people;
}
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", age=" + age +
", car=" + car +
'}';
}
}
main
public static void main(String[] args) throws CloneNotSupportedException {
People old = new People();
old.setName("zhangsan");
old.setAge(23);
Car car = new Car();
car.setName("ferrari");
car.setColor("red");
old.setCar(car);
People clone = (People) old.clone();
System.out.println("源对象:" + old);
System.out.println("新对象:" + clone);
}
结果:引用类型属性也是新的
源对象:People{name='zhangsan', age=23, car=com.company.bean.Car@4554617c}
新对象:People{name='zhangsan', age=23, car=com.company.bean.Car@74a14482}
补充:序列化方式实现
Car
public class Car implements Serializable {
private String name;
private String color;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
People
public class People implements Serializable {
private String name;
private int age;
private Car car;
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 Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", age=" + age +
", car=" + car +
'}';
}
}
main
public static void main(String[] args) throws IOException, ClassNotFoundException {
People old = new People();
old.setName("zhangsan");
old.setAge(23);
Car car = new Car();
car.setName("ferrari");
car.setColor("red");
old.setCar(car);
System.out.println("源对象:" + old);
//序列化
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(outputStream);
oos.writeObject(old);
//反序列化
ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
ObjectInputStream ois = new ObjectInputStream(inputStream);
People clone = (People) ois.readObject();
System.out.println("新对象:" + clone);
}
结果:和深克隆一样,对象和引用类型属性的地址都是新的。
源对象:People{name='zhangsan', age=23, car=com.company.bean.Car@4554617c}
新对象:People{name='zhangsan', age=23, car=com.company.bean.Car@2d98a335}