博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
深拷贝+浅拷贝
阅读量:5221 次
发布时间:2019-06-14

本文共 4181 字,大约阅读时间需要 13 分钟。

implements cloneable ,(实现此接口表示该java类支持克隆,如果没有实现此接口就

调用了clone方法,则会报出来clonenotsupportedexception异常)

 覆写object类中的clone(),并将可见性从protect改为public

 浅拷贝和深拷贝出来新类

 考虑原类和新类的 成员变量是否独立

(两种类型:primitive类型成员变量,引用类型成员变量)

浅拷贝和深拷贝的区别:类中的引用对象是否也implements cloneable, 是否也覆写了

object类中的clone()

相同点:原类implements cloneable, 是否也覆写了object类中的clone()

预备知识?????
java的类型,java的类型分为两大类,一类为primitive,如int,另一类为引用类型,如String,Object等等
java引用类型的存储,java的引用类型都是存储在堆上的。

1.浅复制与深复制概念
⑴浅复制(浅克隆)
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
⑵深复制(深克隆)
被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。

Java代码
  
 
 
public class B

 {


    int a;
    String b;
     public B(int a, String b)

    {


        super();
        this.a = a;
        this.b = b;
    }
}
对这样一个引用类型的实例,我们可以推测,在堆上它的内存存储形式(除去指向class的引用,锁的管理等等内务事务所占内存),应该有一个int值表示a,以及一个引用,该引用指向b在堆上的存储空间。        

为什么要clone?????
有名的GoF设计模式里有一个模式为原型模式,用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.
2.Java的clone()方法
⑴clone方法将对象复制了一份并返回给调用者。一般而言,clone()方法满足:
①对任何的对象x,都有x.clone() !=x//克隆对象与原对象不是同一个对象
②对任何的对象x,都有x.clone().getClass()= =x.getClass()//克隆对象与原对象的类型一样,都是同一个类new出来的不同对象!!!
③如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。
⑵Java中对象的克隆
①为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。
②在派生类中覆盖基类的clone()方法,并声明为public。
③在派生类的clone()方法中,调用super.clone()。
④在派生类中实现Cloneable接口。
一般而言,我们要的clone应该是这样的。copy和原型的内容一样,但是又是彼此隔离的。即在clone之后,改变其中一个不影响另外一个。

Object的clone以及为什么如此实现????????
Object的clone的行为是最简单的。以堆上的内存存储解释的话(不计内务内存),对一个对象a的clone就是在堆上分配一个和a在堆上所占存储空间一样大的一块地方,然后把a的堆上内存的内容复制到这个新分配的内存空间上。
看例子。

 java.lang.Cloneable 接口是一个空接口,该接口用来指明一个对象是否可以进行克隆.实现了该接口的对象可以调用clone()方法来进行对象的浅克隆.

通过调用父类的super.clone()方法(浅拷贝)可以重新生成一个对象,解决因对象引用赋值造成的原对象的修改.

①为什么我们在派生类中覆盖Object的clone()方法时,一定要调用super.clone()呢?在运行时刻,Object中的clone()识别出你要复制的是哪一个对象,然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中。 
继承自java.lang.Object类的clone()方法是浅复制。以下代码可以证明之。

浅拷贝(考虑成员变量是否独立)

类的浅拷贝出来新的类

primitive类型成员变量在两个类中是独立的,虽然值是相等的,但

是改变其中一个类中的primitive值不会影响另一个类的primitive值。

引用类型成员变量在两个类中是同一个,也是同一个堆空间,

即:改变其中一个类中的引用值,也就是改变了另一个类的引用值。

class User 
{
    String name;
    int age;
}
class Account
implements Cloneable 
{
    User user;
    long balance;
    @Override
    public
Object clone()
throws CloneNotSupportedException
   {
 
 
 
  
 
 
 return super.clone();
 
 
 
 }
}
//下面是测试类里的代码
User user = new User(); 

 
user.name = "user"; 

 
user.age = 20;

 
Account account = new Account(); 

 
account.user = user; 

 
account.balance = 10000; 

 
// copy. 

 
Account copy = (Account) account.clone(); 

 

 
// balance因为是primitive,所以copy和原型是相等且独立的。 

 
Assert.assertEquals
(copy.balance,account.
balance); //为真!

 
copy.balance =20000;

// 改变copy不影响primitive类型。 

 
Assert.assertTrue
(copy.balance
!=
account.balance); //为真!

 
 

 
// user因为是引用类型,所以copy和原型的引用是同一的。 

 
Assert.assertTrue(copy.user == account.user); //为真!

 
copy.user.age = 22; 

 
// 改变的是同一个东西。 

 
Assert.assertEquals
(copy.user.age, account.user.age); //为真!

又一例子如下:

 class User implements Cloneable 


        String name; 
        int age; 
     
        @Override 
        publicObject clone() throws CloneNotSupportedException

 { 
            return super.clone(); 
        } 
    } 

//测试类如下:

// user.  
User user = new User();  
user.name = "user";  
user.age = 20;  
 
  
 
// copy 
 
User copy = (User) user.clone(); 
 
 
// age因为是primitive,所以copy和原型是相等且独立的。 
 
Assert.assertEquals(copy.age, user.age); //为真!
 
copy.age = 30; 
 
// 改变copy不影响原型。 
 
Assert.assertTrue(copy.age != user.age); //为真
 
 
 
// name因为是引用类型,所以copy和原型的引用是同一的。 
 
Assert.assertTrue(copy.name == user.name); //为真!
 
// String为不可变类。没有办法可以通过对copy.name的字符串的操作改变这个字符串。 
 
// 改变引用新的对象不会影响原型。 
 
copy.name = "newname"; //这里应该会报错吧
 
Assert.assertEquals("newname", copy.name); //为假,因为string类型不可变!
 
Assert.assertEquals("user", user.name); //为真!
 可见,在考虑浅clone时,primitive和不可变对象类型是可以同等对待的。
深拷贝()

类的深拷贝出来新的类

primitive类型成员变量在两个类中是独立的,虽然值是相等的,但

是改变其中一个类中的primitive值不会影响另一个类的primitive

值。

引用类型成员变量在两个类中是独立的,是两个不同的堆空间,

即:改变其中一个类中的引用值不会影响另一个类的引用类型。

深拷贝的实现方法:
把引用对象也拷贝一次,那么这就是深拷贝!也就是把全部引用对象都浅拷贝一次,就得到深拷贝

class User implements Cloneable {


            String name;
            int age;

            @Override
            public User clone() throws CloneNotSupportedException {

                    return (User) super.clone();
            }
    }

    class Account implements Cloneable {

            User user;
            long balance;

            @Override
            public Account clone() throws CloneNotSupportedException {

                    Account account = null;

                    account = (Account) super.clone();
                    if (user != null) {

                            account.user = user.clone();
                 

转载于:https://www.cnblogs.com/baoendemao/p/3804682.html

你可能感兴趣的文章
关于Matchvs一些使用心得与建议
查看>>
Gson获取json串中的key-value
查看>>
创建spring boot项目
查看>>
Behave + Selenium(Python) 四
查看>>
系统的横向结构(AOP)
查看>>
linux常用命令
查看>>
有序链表的归并 分类: 链表 2015-06-...
查看>>
A Plug for UNIX 分类: POJ ...
查看>>
寒假作业01
查看>>
Linux常用命令
查看>>
正确适配苹果ATS审核要求的姿势
查看>>
NHibernate.3.0.Cookbook第四章第6节的翻译
查看>>
例1-1
查看>>
Java 8 新特性之 Stream&forEach&map&filter&limit&sorted&统计函数&Collectors&并行(parallel)程序(转)...
查看>>
Windows建立Cucumber和Ruby测试环境
查看>>
HBase中MVCC的实现机制及应用情况
查看>>
马达调速器,直流马达调速器,直流调速器
查看>>
【转】概要设计怎么写
查看>>
前端编码规范小记
查看>>
C#编程(二十五)----------接口
查看>>