JAVA学习总结之简单复制、浅复制、深复制

java中的数据类型分为两种:基本类型,引用类型。基本类型分为四类八种,分别如下:
- 整型 byte short int long
- 浮点型 float double
- 逻辑型 boolean
- 字符型 char
除这四类八种之外的所有对象都属于引用类型,其实本质上引用类型是一大堆有组织有结构的基本类型的集合。引用类型追究其本源,也是由基本类型所组成的。


简单复制

简单复制从字面上就很容易解释,将一个值或者一个对象,不加处理的赋值给另一个值或者对象,就是简单复制。例如:

int a = 10;
int b = a;
a = 100;
System.out.println("a: " + a);
System.out.println("b: " + b);

输出的结果显然为:

a: 100
b: 10

这是因为在基本类型在内存里面是开辟一个小空间,将基本类型的值直接存放在该空间里的。例如 int a = 10; 即是开辟一个4字节的空间,将10转换成二进制的形式存在该4字节的空间中的(存的是补码)。而 int b = a; 即是另外开辟4字节的空间,将a空间里面的二进制原封不动的复制到b空间里面去。a = 100; 将a空间里面的值改变成100的二进制形式(补码)。此时输出a、b,则输出的是a、b自己空间的值。也就是100、10。
简单复制对于基本类型的数据来说很easy,但是真正放到引用类型上面还会如基本类型一样的简单吗?不妨看看下面一段代码:

//假设已经有一个对象SimpleCope,里面有一个属性 int a
SimpleCope s1 = new SimpleCope();
s1.a = 10;
SimpleCope s2 = s1;
s1.a = 100;
System.out.println("s1.a: " + s1.a);
System.out.println("s2.a: " + s2.a);

输出结果为:

s1.a: 100
s2.a: 100

咦?很奇怪,不应该还是100和10吗?为什么这次两个都变成了100?要想弄清楚这个原因,还是要从内存的角度上考虑。引用类型实际上分成两个部分,一个是引用,一个是对象,我们在程序中用的其实是引用,我们通过引用去控制、改变对象的值。对象存在于堆中(大部分如此)。SimpleCope s1 = new SimpleCope(); 这一步其实做了两件事,第一件事是在堆上开辟了一个空间,里面存了SimpleCope这个对象。另一件事是开辟了一个小空间(一般在栈上)用于存放对象的引用,引用指向对象(类似于C中的指针)。s1.a = 10; 实际上是在对象的空间里面将其中属于a的那部分空间,写入10的二进制形式(补码)。SimpleCope s2 = s1; 新建一个引用,该引用指向s1的引用,也即是指向和s1所指向的对象。此时s2所指的对象的a属性也为10;s1.a = 100;将对象里面a的值从10换成100;注意此时s2指向的对象也是这个对象,那么s2.a 也是修改以后的100;这就合理的解释了为什么结果是100、100。

简单复制

从上述两个例子可以看得出来,简单复制只能复制基本类型,如果真的想去复制引用类型,那么可能想要的结果并不能满足。

浅复制

在介绍浅复制前,先将结论告诉大家,方便等等讲解的时候思考。浅复制其实就是将对象里面所有的基本类型的值都复制,将引用类型的引用复制。也即浅复制只能复制一个对象里面的基本类型,而不能复制对象里面的引用类型属性。

public class ShallowCopy implements Cloneable {

    private int a;

    ShallowCopy shallowCopy;

    ShallowCopy(int a) {
        this.a = a;
        shallowCopy = new ShallowCopy();
        shallowCopy.a = a;
    }

    ShallowCopy() {

    }

    public static void main(String[] args) throws CloneNotSupportedException {
        ShallowCopy s1 = new ShallowCopy(10);
        ShallowCopy s2 = (ShallowCopy) s1.clone();
        s1.a = 100;
        s1.shallowCopy.a = 100;
        System.out.println("s1.a: " + s1.a + "; s1.shallowCopy.a: " + s1.shallowCopy.a);
        System.out.println("s2.a: " + s2.a + "; s2.shallowCopy.a: " + s2.shallowCopy.a);
    }
}

输出的结果为:

s1.a: 100; s1.shallowCopy.a: 100
s2.a: 10; s2.shallowCopy.a: 100

解释一下:首先写了一个类ShallowCopy,该类实现Cloneable接口,主要是想通过Object.clone方法的,该方法需要子类实现Cloneable接口,否则将会抛出CloneNotSupportedException异常。其中如果子类不去修改Object的clone方法,那么该方法是java自身实现的对象浅复制。我们还是先new 出一个ShallowCopy对象,另ShallowCopy对象中的属性a赋值为10,同时将ShallowCopy对象中的属性ShallowCopy对象的a属性赋值为10(有点绕口,哈哈~)。ShallowCopy s2 = (ShallowCopy) s1.clone();开始浅复制。复制的对象赋值给s2,也即s2现在指向新的对象。s1.a = 100,将s1指向的对象中的a属性赋值成100。由于s2现在所指向的对象和s1所指向的对象不是同一个对象,所以s1改变a的值并不影响s2中a的值,这时候s2的值还是10。s1.shallowCopy.a = 100;改变s1对象中的shallowCopy对象的属性a,注意,注意shallowCopy在s1中存的不是对象,而是引用,其真正的对象在内存的另一块区域。这句话执行了之后,远在另一块区域的shallowCopy对象的属性a由一开始的10改变成了100。同时由于是浅复制,所以对于复制的对象中的引用类型的属性,只复制其引用,这意味了在s2对象中的引用类型shallowCopy也是指向s1对象中的引用类型shallowCopy的对象。所以此时s2.shallowCopy.a也发生了改变,从10变成了100;

浅复制

深复制

其实介绍到这里了,如果前面的知识都听明白了,那么深复制也就不言而喻了。深复制其实就是真正的复制,完全的复制,不仅复制了对象里面的基本数据类型,也完全复制了对象里面的引用类型。实现深度复制的办法有很多,例如可以通过IO流去深度复制对象,也可以通过一些特殊对象的特殊方法进行深复制,例如Collections有一个copy方法。这里就不一一介绍了。记住,深度复制是将对象的所有全部都复制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值