概述
简单描述一下对象的实例化过程。
创建对象的时候,或者说在实例化对象的时候 Person 类有年龄和学生类
int age = 18;
Student stu1 = new Student();
比如此时创建一个 age 对象,一个Student 对象,在虚拟机中,会在堆中开一个对象空间,里面包含了对象的属性信息,当给基本数据类型赋值时,会将赋的值存储在堆中,然后在栈中会创建一个对象名保存着堆中数据的地址。简单说就是指向堆中的对象。给引用数据类型赋值时,会将赋的值存在方法区的常量池中,而堆保存的是方法区的地址,栈中同样保存的是堆中的地址。
拷贝
浅拷贝:浅拷贝会在堆上创建一个新的对象,不过,如果原对象内部的属性是引用数据类型的话,浅拷贝会直接赋值内部对象的引用地址,也就是说原对象和拷贝对象指向同一个对象。
深拷贝:深拷贝会完全赋值整个对象,包括这个对象的所有的内部对象。
举个通俗的例子
此时你的电脑桌面上有两个东西,一个是一个压缩包,里面有很多东西,比如图片压缩包等,还有一个是一款游戏的快捷方式。
浅拷贝,就像是你把快捷方式复制粘贴了一遍,无论你使用哪个都可以 XX!启动!,因为他们都是指向游戏本体程序的,属于两个对象指向同一个内部对象。
深拷贝,就像是你把压缩包复制了一遍,你不管将哪一个压缩包拷贝到U盘都可以在另一台电脑使用。因为两个都是独立的对象,只不过一模一样。
图片来源:JavaGuide
实例代码
浅拷贝
/**
* 地址类
*
*/@Data
public class Address implements Cloneable{private String name;@Overridepublic Address clone() {try {return (Address) super.clone();} catch (CloneNotSupportedException e) {throw new AssertionError();}}
}
/**
* 人类
*/@Data
public class Person implements Cloneable {private Address address;@Overridepublic Person clone() {try {return (Person) super.clone();} catch (CloneNotSupportedException e) {throw new AssertionError();}}
}
/**
* 测试
*/
Person person1 = new Person();
Person clone = person1.clone();
System.out.println(person1.getAddress() == clone.getAddress());
输出为 true,表示两个对象的内部对象是同一个对象。
修改为深拷贝 ,我们将Person 类中的 Address 对象也进行了拷贝,相当于我不久将快捷方式也复制了一次,也将游戏的实际程序主体也进行了复制。
@Overridepublic Person clone() {try {Person person = (Person) super.clone();person.setAddress(person.getAddress().clone());return person;} catch (CloneNotSupportedException e) {throw new AssertionError();}}
Person person = new Person(new Address());
Person clone = person.clone();
System.out.println(clone.getAddress() == person.getAddress());
输出为 false,说明内部对象已经不是同一个对象了,内部对象也被拷贝的一次。
参考资料:Java 面试指南 | JavaGuide