• JAVA Clone复制对象


    谈到了对象的克隆,就不得不说为什么要对对象进行克隆。Java中所有的对象都是保存在堆中,而堆是供全局共享的。也就是说,如果同一个Java程序的不同方法,只要能拿到某个对象的引用,引用者就可以随意的修改对象的内部数据(前提是这个对象的内部数据通过get/set方法曝露出来)。有的时候,我们编写的代码想让调用者只获得该对象的一个拷贝(也就是一个内容完全相同的对象,但是在内存中存在两个这样的对象),有什么办法可以做到呢?当然是克隆咯。

    import java.io.Serializable;
    
    public class Apple implements Cloneable,Serializable {
        private static final long serialVersionUID = 1L;
        
        private String locality;
    
        public String getLocality() {
            return locality;
        }
    
        public void setLocality(String locality) {
            this.locality = locality;
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }

    上面的代码,简单的构建了一个Apple对象,并实现了Cloneable及Serializable接口,并重写clone()方法。

    接着再构建一个Fruit对象,里面有一个Apple属性。

    import java.io.Serializable;
    
    public class Fruit implements Cloneable,Serializable{
    	private static final long serialVersionUID = 1L;
    
    	private String fruitName;
    	
    	private Apple apple;
    	
    	public Apple getApple() {
    		return apple;
    	}
    
    	public void setApple(Apple apple) {
    		this.apple = apple;
    	}
    
    	public String getFruitName() {
    		return fruitName;
    	}
    
    	public void setFruitName(String fruitName) {
    		this.fruitName = fruitName;
    	}
    
    	@Override
    	protected Fruit clone() throws CloneNotSupportedException {
    		
    		return (Fruit)super.clone();
    	}
    }
    

     接着复制一下对象:

    Fruit fruit = new Fruit();
    fruit.setFruitName("Apple");

       Apple apple = new Apple();
       apple.setLocality("China");

    fruit.setApple(apple);
    		
    Fruit fruit2 = fruit.clone();
    		
    System.out.println("Fruit = "+(fruit==fruit2));
    System.out.println("Fruit's apple="+(fruit.getApple()==fruit2.getApple()));

    结果如下:

    Fruit = false
    Fruit's apple=true

    很明显,这里的复制是浅复制(shallow clone)。fruit2内的apple属性与fruit内的apple属性是同一个对象,只复制了引用的地址。

    而深克隆,就是非浅克隆。克隆除自身以外所有的对象,包括自身所包含的所有对象实例。至于深克隆的层次,由具体的需求决定,也有“N层克隆”一说。

    但是,所有的基本(primitive)类型数据,无论是浅克隆还是深克隆,都会进行原值克隆。毕竟他们都不是对象,不是存储在堆中。注意:基本数据类型并不包括他们对应的包装类。

    如果我们想让对象进行深度克隆,我们可以这样修改Fruit类的clone()方法。

    @Override
    protected Fruit clone() throws CloneNotSupportedException {
    	    Fruit fruit = (Fruit)super.clone();
    	    fruit.apple = (Apple)fruit.getApple().clone();
    	    return fruit;
    	    
    }
    

    这样就可以实现了,如果类层次较深,这样写就很麻烦。

    接下来要重点介绍一下使用java.lang.Serializable来实现对象的深度克隆。

    首先,我们编写一个工具类并提供cloneTo()方法。

    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    
    public class BeanDeepCloneUtil {
    
    	@SuppressWarnings("unchecked")
    	public static <T> T cloneTo(T src) {
    		ByteArrayOutputStream memoryBuffer = new ByteArrayOutputStream();
    		ObjectOutputStream outputStream = null;
    		ObjectInputStream inputStream = null;
    
    		T destination = null;
    		try {
    			outputStream = new ObjectOutputStream(memoryBuffer);
    			outputStream.writeObject(src);
    			outputStream.flush();
    			inputStream = new ObjectInputStream(new ByteArrayInputStream(
    					memoryBuffer.toByteArray()));
    
    			destination = (T) inputStream.readObject();
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (ClassNotFoundException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} finally {
    
    			try {
    				if (outputStream != null) {
    					outputStream.close();
    					outputStream=null;
    				}
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    			
    			try {
    				if (inputStream != null) {
    					inputStream.close();
    					inputStream=null;
    				}
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    
    		return destination;
    	}
    
    }
    

     接下来我们测试一下是否能通过这个工具来实现深度克隆。

    Apple apple = new Apple();
    apple.setLocality("China");
    
    Fruit fruit = new Fruit();
    fruit.setFruitName("Apple");
    fruit.setApple(apple);
    
    
    Fruit fruit3 = BeanDeepCloneUtil.cloneTo(fruit);
    System.out.println("Fruit = "+(fruit==fruit3));
    System.out.println("Fruit's apple="+(fruit.getApple()==fruit3.getApple()));

     运行结果如下:

    Fruit = false
    Fruit's apple=false

  • 相关阅读:
    Python分析网页中的<a>标签
    Python3.X爬虫
    如何使你的窗体样式固定,不因系统设定而变化
    C# 窗体内有子控件时鼠标检测
    VS新建项目工具箱图标丢失问题
    在c#中使用bitblt显示图片
    DotNetBar 中Ribbon汉化
    汉化DotNetBar中控件的系统文本
    castle动态代理的使用
    FastReport 套打全攻略
  • 原文地址:https://www.cnblogs.com/foxting/p/8442210.html
Copyright © 2020-2023  润新知