讨论这个话题前,我们先回顾一些先验知识:
Java中的数据类型分为:基本数据类型,引用数据类型。
对于两种数据类型,在进行赋值操作,用作方法参数或返回值时,会有值传递和引用(地址)传递的差别。
基本数据类型:
四种整数类型(byte、short、int、long)
两种浮点数类型(float、double)
一种字符类型(char)
一种布尔类型(boolean)
引用数据类型:
类、接口类型、数组类型、枚举类型、注解类型
基本数据类型在创建时,在栈上给其划分一块内存,将数值直接存储在栈上。
引用数据类型在被创建时,首先要在栈上给其引用分配一块内存,而对象的具体信息都存储在堆内存上,然后由栈上面的引用指向堆中对象的地址。
浅拷贝:
(1)对于基本数据类型的成员变量:浅拷贝直接进行值传递,对其中一个对象的修改,并不会影响令一个对象。
(2)对于引用类型的成员变量:浅拷贝进行引用传递,即仅将该成员变量的引用值(内存地址)复制一份发给新的对象,在一个对象中修改该成员变量会影响到令一个成员变量的值。
/* 拷贝构造方法实现浅拷贝 */
public class CopyConstructor {
public static void main(String[] args) {
Age a=new Age(20);
Person p1=new Person(a,"小冬瓜");
Person p2=new Person(p1);
System.out.println("p1是"+p1);
System.out.println("p2是"+p2);
//修改p1的各属性值,观察p2的各属性值是否跟随变化
p1.setName("小傻瓜");
a.setAge(99);
System.out.println("修改后的p1是"+p1);
System.out.println("修改后的p2是"+p2);
}
}
class Person{
//两个属性值:分别代表值传递和引用传递
private Age age;
private String name; //注意Name和age的方法不同
public Person(Age age,String name) {
this.age=age;
this.name=name;
}
//拷贝构造方法
public Person(Person p) {
this.name=p.name;
this.age=p.age;
}
public void setName(String name) {
this.name=name;
}
public String toString() {
return this.name+" "+this.age;
}
}
class Age{
private int age;
public Age(int age) {
this.age=age;
}
public void setAge(int age) {
this.age=age;
}
public int getAge() {
return this.age;
}
public String toString() {
return getAge()+"";
}
}
运行结果是:
p1是小冬瓜 20
p2是小傻瓜 20
修改后的p1是小冬瓜 99
修改后的p2是小傻瓜 99
结果分析:
name 的数据类型是String属于常量;
age 的数据类型是一个构造类型。
深拷贝:
深拷贝对引用数据类型的成员变量的对象图中所有的对象都开辟了内存空间;而浅拷贝只是传递地址指向,新的对象并没有对引用数据类型创建内存空间。
因为创建内存空间和拷贝整个对象图,所以深拷贝相比于浅拷贝速度较慢并且花销较大。