zoukankan      html  css  js  c++  java
  • 浅谈Java中的深克隆和浅克隆(阿里面试)

    在最近的秋招中,阿里和多益网络都问到了这个问题,虽然很简单,但是我还是想总结一下,感兴趣的可以看一下我的个人博客网站(Spring+MyBatis+redis+nginx+mysql)(适合菜鸟),最近会抽空把最近面试遇到的问题总结一下。

    本文针对问题:深克隆和浅克隆的区别和实现方式?(阿里电面,多益网络的选择题)

    Talk is cheap

    最近不止一次遇见深浅克隆(深复制,浅复制)的问题,除了印象中有个clone方法外一脸懵逼!!!克隆(复制)在Java中是一种常见的操作,目的是快速获取一个对象副本。克隆分为深克隆和浅克隆。

    浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。

    深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

    总之深浅克隆都会在堆中新分配一块区域,区别在于对象属性引用的对象是否需要进行克隆(递归性的)。

    Show you my picture

    pos:当前对象的地址;

    son:son属性所指向的地址;

    name:对象的name属性。

    Show you my code

    case1:

    public class Son implements Serializable , Cloneable{
        private String name;
        private Son son;
        public Son() {
            super();
        }
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Son getSon() {
            return son;
        }
    
        public void setSon(Son son) {
            this.son = son;
        }
    
        @Override
        public String toString() {
            return super.toString();
        }
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    

    测试

    public static void main(String[] args) throws Exception{
    	// 创建父亲(LiLiu),儿子(LiWu),孙子(LiLiu)并关联
    	Son father = new Son();
    	father.setName("LiSi");
    	Son son = new Son();
    	son.setName("LiWu");
    	Son grandSon = new Son();
    	grandSon.setName("LiLiu");
    	father.setSon(son);
    	son.setSon(grandSon);
    	// 调用clone方法
    	Son fatherCopy =  (Son) father.clone();
    	boolean flag1 = fatherCopy==father;
    	boolean flag2 = fatherCopy.getSon() == son;
    	boolean flag3 = fatherCopy.getSon().getSon() == grandSon;
    	// 比较克隆后的地址
    	System.out.println(flag1);// false
    	System.out.println(flag2);// true
    	System.out.println(flag3);// true
    	// 比较Name
    	flag1= fatherCopy.getName()==father.getName();
    	flag2 = fatherCopy.getSon().getName() == son.getName();
    	flag3 = fatherCopy.getSon().getSon().getName() == grandSon.getName();
    	System.out.println(flag1);// true
    	System.out.println(flag2);// true
    	System.out.println(flag3);// true
    	
    	//将对象写到流里    
    	ByteArrayOutputStream byteOut=new ByteArrayOutputStream();    
    	ObjectOutputStream objOut=new ObjectOutputStream(byteOut);    
    	objOut.writeObject(father);
    	//从流里读出来    
    	ByteArrayInputStream byteIn=new ByteArrayInputStream(byteOut.toByteArray());    
    	ObjectInputStream objInput=new ObjectInputStream(byteIn);
        fatherCopy = (Son) objInput.readObject();
    	flag1= fatherCopy==father;
    	flag2 = fatherCopy.getSon() == son;
    	flag3 = fatherCopy.getSon().getSon() == grandSon;
    	System.out.println(flag1);// false
    	System.out.println(flag2);// false
    	System.out.println(flag3);// false
    	
    	// 比较Name
    	flag1= fatherCopy.getName()==father.getName();
    	flag2 = fatherCopy.getSon().getName() == son.getName();
    	flag3 = fatherCopy.getSon().getSon().getName() == grandSon.getName();
    	System.out.println(flag1);// false
    	System.out.println(flag2);// false
    	System.out.println(flag3);// false
    }
    

    从上文代码及运行结果不难看出,如果对象实现Cloneable并重写clone方法不进行任何操作时,调用clone是进行的浅克隆。而使用对象流将对象写入流然后再读出是进行的深克隆。

    思考:既然实现Cloneable接口并重写clone接口只能进行浅克隆。但是如果类的引用类型属性(以及属性的引用类型属性)都进行浅克隆,直到没有引用类型属性或者引用类型属性为null时,整体上就形成了深克隆。既对象的引用类型属性和属性的应用类型属性都实现Coloneable,重写clone方法并在clone方法中进行调用。

    protected Object clone() throws CloneNotSupportedException {
          Son result = (Son) super.clone();
    	if (son != null) {
    		result.son = (Son) son.clone();
    	}
        return result;
    }
    

    说几句废话

    个人认为,在选择深克隆方法时,应根据对象的复杂程度,如引用类型属性是否有多层引用类型属性关系。如果对象只有一层或者两层引用类型的属性,选择思考中所提到的方法较为方便,反之则使用对象流。

  • 相关阅读:
    [转发]深入理解git,从研究git目录开始
    iOS系统网络抓包方法
    charles抓包工具
    iOS多线程中performSelector: 和dispatch_time的不同
    IOS Core Animation Advanced Techniques的学习笔记(五)
    IOS Core Animation Advanced Techniques的学习笔记(四)
    IOS Core Animation Advanced Techniques的学习笔记(三)
    IOS Core Animation Advanced Techniques的学习笔记(二)
    IOS Core Animation Advanced Techniques的学习笔记(一)
    VirtualBox复制CentOS后提示Device eth0 does not seem to be present的解决方法
  • 原文地址:https://www.cnblogs.com/liqiangchn/p/9465186.html
Copyright © 2011-2022 走看看