深拷贝和浅拷贝区别
在 Java 中,**深拷贝(Deep Copy)和浅拷贝(Shallow Copy)**是指对象复制时,复制的方式和结果的不同。理解这两者的区别非常重要,特别是在处理复杂对象时。浅拷贝和深拷贝的主要区别在于对象内部引用的处理方式。
1. 浅拷贝(Shallow Copy)
浅拷贝是指复制对象时,只复制对象本身,而不会复制对象内部引用的其他对象。也就是说,源对象和目标对象内部的引用类型变量(如数组、对象等)指向相同的内存地址(即它们引用的是相同的对象)。因此,源对象和目标对象共享同一份数据。
浅拷贝的特点:
- 复制的是对象的“引用”,而非对象所指向的数据。
- 对象的引用类型字段仍然指向原始对象的内存地址(即浅拷贝并没有创建新的引用对象)。
浅拷贝的代码示例:
class Address {
String city;
Address(String city) {
this.city = city;
}
}
class Person {
String name;
Address address;
Person(String name, Address address) {
this.name = name;
this.address = address;
}
// 浅拷贝方法
public Person shallowCopy() {
return new Person(this.name, this.address); // 复制的是引用,address 地址相同
}
}
public class ShallowCopyExample {
public static void main(String[] args) {
Address address = new Address("New York");
Person person1 = new Person("Alice", address);
// 浅拷贝
Person person2 = person1.shallowCopy();
System.out.println(person1.name); // 输出: Alice
System.out.println(person2.name); // 输出: Alice
System.out.println(person1.address.city); // 输出: New York
System.out.println(person2.address.city); // 输出: New York
// 修改 person2 的 address
person2.address.city = "Los Angeles";
// 由于浅拷贝,person1 和 person2 的 address 是同一个对象
System.out.println(person1.address.city); // 输出: Los Angeles
System.out.println(person2.address.city); // 输出: Los Angeles
}
}
输出结果:
Alice
Alice
New York
New York
Los Angeles
Los Angeles
说明:
person1
和person2
的address
引用指向相同的Address
对象,因此修改person2
的address
会影响person1
的address
。- 这是因为我们进行了浅拷贝,
address
字段只是引用了相同的内存地址。
2. 深拷贝(Deep Copy)
深拷贝是指复制对象时,不仅复制对象本身,而且复制对象内部引用的其他对象。也就是说,深拷贝会创建对象及其所引用的所有对象的副本,源对象和目标对象之间完全独立,它们不会共享任何引用对象。
深拷贝的特点:
- 复制的是对象及其所有引用的对象,确保新对象的所有引用都指向新创建的对象。
- 目标对象与源对象在内存中完全独立,修改目标对象的属性不会影响源对象。
深拷贝的代码示例:
class Address {
String city;
Address(String city) {
this.city = city;
}
// 深拷贝方法
public Address deepCopy() {
return new Address(this.city); // 创建一个新的 Address 对象
}
}
class Person {
String name;
Address address;
Person(String name, Address address) {
this.name = name;
this.address = address;
}
// 深拷贝方法
public Person deepCopy() {
// 创建新的 Person 对象,并对 address 进行深拷贝
return new Person(this.name, this.address.deepCopy());
}
}
public class DeepCopyExample {
public static void main(String[] args) {
Address address = new Address("New York");
Person person1 = new Person("Alice", address);
// 深拷贝
Person person2 = person1.deepCopy();
System.out.println(person1.name); // 输出: Alice
System.out.println(person2.name); // 输出: Alice
System.out.println(person1.address.city); // 输出: New York
System.out.println(person2.address.city); // 输出: New York
// 修改 person2 的 address
person2.address.city = "Los Angeles";
// 由于深拷贝,person1 和 person2 的 address 是不同的对象
System.out.println(person1.address.city); // 输出: New York
System.out.println(person2.address.city); // 输出: Los Angeles
}
}
输出结果:
Alice
Alice
New York
New York
New York
Los Angeles
说明:
person1
和person2
的address
引用指向不同的对象,person2
修改address
不会影响person1
。- 这是因为我们进行了深拷贝,
address
字段指向了新创建的Address
对象。
3. 深拷贝与浅拷贝的对比
引用对象的处理 | 只复制对象本身,不复制对象引用的其他对象。 | 复制对象本身及其所有引用的对象,确保每个引用指向新的对象。 |
对象之间的关系 | 源对象和目标对象共享相同的引用对象。 | 源对象和目标对象独立,互不影响。 |
修改影响 | 修改目标对象会影响源对象,因为它们共享同一引用对象。 | 修改目标对象不会影响源对象,因为它们不共享任何引用对象。 |
性能 | 浅拷贝比深拷贝更高效,因为只涉及对象本身和引用的复制。 | 深拷贝需要复制整个对象图,性能开销较大。 |
4. 深拷贝和浅拷贝的实际应用
-
浅拷贝:
- 适用于不修改对象内部引用的情况下。比如,你只需要复制对象的基本数据,且不关心对象引用类型字段的变化。
- 常见场景:复制对象用于某些不改变内部引用的操作,如在多线程中共享不可变的对象。
-
深拷贝:
- 适用于需要复制对象及其引用对象,且这些引用对象的状态不应该被共享的场景。例如,修改一个对象的内部引用数据时不希望影响到其他对象。
- 常见场景:当对象中包含嵌套的可变对象时,深拷贝能确保每个对象都被独立复制,防止修改一个对象影响到其他对象。
Java碎碎念 文章被收录于专栏
来一杯咖啡,聊聊Java的碎碎念呀