浅克隆和深克隆有什么区别?
什么是克隆?
在编程中,克隆是指创建一个与原始对象相同的新对象。这个新对象通常具有与原始对象相同的属性和方法,但是它们是两个不同的对象,它们在内存中的位置不同。在 Java 中,可以通过实现 Cloneable 接口和重写 clone() 方法来实现对象的克隆。
什么是浅克隆和深克隆?它们有什么区别?
在 Java 中,克隆可以分为深克隆和浅克隆两种。它们的区别在于克隆出来的新对象是否与原始对象共享引用类型的属性。具体来说:
-
浅克隆:克隆出来的新对象与原始对象共享引用类型的属性。也就是说,新对象中的引用类型属性指向的是原始对象中相同的引用类型属性。如果修改了新对象中的引用类型属性,原始对象中的相应属性也会被修改。在 Java 中,可以通过实现 Cloneable 接口和重写 clone() 方法来实现浅克隆。
-
深克隆:克隆出来的新对象与原始对象不共享引用类型的属性。也就是说,新对象中的引用类型属性指向的是新的对象,而不是原始对象中相同的引用类型属性。如果修改了新对象中的引用类型属性,原始对象中的相应属性不会被修改。
浅克隆实现
public class CloneDemo { public static void main(String[] args) { Person p1 = new Person(); p1.setName("张三"); p1.setAge(18); Address address = new Address(); address.setCity("北京"); p1.setAddress(address); // 克隆 p1 对象 Person p2 = p1.clone(); System.out.println(p1 == p2); // false System.out.println(p1.getAddress() == p2.getAddress()); // true } } class Person implements Cloneable { private String name; private int age; private Address address; // 引用类型 @Override public Person clone() { Person person = null; try { person = (Person) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return person; } // 忽略 getter 和 setter 方法 }
class Address {
private String city;
// 忽略 getter 和 setter 方法
}
## 深克隆实现
深克隆的实现方法有很多,比如以下几个:
1. 所有引用属性都实现克隆,整个对象就变成了深克隆。
2. 使用 JDK 自带的字节流序列化和反序列化对象实现深克隆。
3. 使用第三方工具实现深克隆,比如 Apache Commons Lang。
4. 使用 JSON 工具,如 GSON、FastJSON、Jackson 序列化和反序列化对象实现深克隆。
比较常用的深克隆实现是,第一种让所有引用类型的属性实现克隆,和第四种使用 JSON 工具实现深克隆。
> 在 Java 中,序列化是指将对象转换为字节流的过程,以便可以将其存储在文件中、通过网络发送或在进程之间传递。反序列化是指将字节流转换回对象的过程。
### 深克隆实现一:引用属性实现克隆
```java
import lombok.Getter;
import lombok.Setter;
public class CloneDemo {
public static void main(String[] args) {
Person p1 = new Person();
p1.setName("张三");
p1.setAge(18);
// 引用类型
Address address = new Address();
address.setCity("北京");
p1.setAddress(address);
// 克隆 p1 对象
Person p2 = p1.clone();
// 对比引用类型的地址值是否相同
System.out.println(p1.getAddress() == p2.getAddress()); // false
}
}
@Getter
@Setter
class Person implements Cloneable {
private String name;
private int age;
private Address address; // 引用类型
@Override
public Person clone() {
Person person = null;
try {
person = (Person) super.clone();
// 克隆引用类型
person.setAddress(person.getAddress().clone());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return person;
}
}
@Getter
@Setter
class Address implements Cloneable {
private String city;
@Override
public Address clone() {
Address address = null;
try {
address = (Address) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return address;
}
}
深克隆实现二:使用 JSON 工具
使用 Google 的 GSON(JSON)工具类来实现:
import com.google.gson.Gson;
import lombok.Getter;
import lombok.Setter;
public class CloneDemo {
public static void main(String[] args) {
Person p1 = new Person();
p1.setName("张三");
p1.setAge(18);
// 引用类型
Address address = new Address();
address.setCity("北京");
p1.setAddress(address);
// JSON 工具类
Gson gson = new Gson();
// 序列化
String json = gson.toJson(p1);
// 克隆 p1 对象 | 反序列化
Person p2 = gson.fromJson(json, Person.class);
// 对比引用类型的地址值是否相同
System.out.println(p1.getAddress() == p2.getAddress()); //false
}
}
@Getter
@Setter
class Person implements Cloneable {
private String name;
private int age;
private Address address; // 引用类型
@Override
public Person clone() {
Person person = null;
try {
person = (Person) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return person;
}
}
@Getter
@Setter
class Address {
private String city;
}
小结
克隆是指创建一个与原始对象相同的新对象。克隆可以分为深克隆和浅克隆两种。它们的区别在于克隆出来的新对象是否与原始对象共享引用类型的属性。
本文已收录至《Java面试突击》,专注 Java 面试 100 年,查看更多:www.javacn.site