Java学习笔记14

Object类是所有类、数组、枚举类的父类,是类层次结构的根类。每个类都使用Object作为超类。所有对象(包括


数组)都实现这个类的方法。 


Object类实现了以下方法:

技术分享

我们来看看源码中clone()方法是如何定义的:


protected native Object clone() throws CloneNotSupportedException;


  我们看到clone()方法前用了native来修饰,说明native方法的效率一般来说高于Java中的非native方法。其次用了

        protected访问权限来修饰,也就是说你想应用clone()方法必须继承Object,在Java中所有的类缺省继承Object类,

       所以可以忽略。

zui  接着我们看看clone()方法的作用,在官方文档是这样说的:

创建并返回此对象的一个副本。“副本”的准确含义可能依赖于对象的类。这样做的目的是,对于任何对象x

表达式:
x.clone() != x
为 true。

表达式:
x.clone().getClass() == x.getClass()
也为 true,但这些并非必须要满足的要求。

一般情况下:
x.clone().equals(x)
true,但这并非必须要满足的要求。

按照惯例,返回的对象应该通过调用super.clone 获得。如果一个类及其所有的超类(Object 除外)都遵守此约


定,则 x.clone().getClass() == x.getClass()


按照惯例,此方法返回的对象应该独立于该对象(正被复制的对象)。要获得此独立性,在super.clone 返回对象


之前,有必要对该对象的一个或多个字段进行修改。这通常意味着要复制包含正在被复制对象的内部“深层结构”的


所有可变对象,并使用对副本的引用替换对这些对象的引用。如果一个类只包含基本字段或对不变对象的引用,那


么通常不需要修改 super.clone 返回的对象中的字段。


Object 类的clone 方法执行特定的复制操作。首先,如果此对象的类不能实现接口 Cloneable,则会抛出


  CloneNotSupportedException。注意,所有的数组都被视为实现接口Cloneable。否则,此方法会创建此对象的类的


一个新实例,并像通过分配那样,严格使用此对象相应字段的内容初始化该对象的所有字段;这些字段的内容没有


被自我复制。所以,此方法执行的是该对象的“浅表复制”,而不“深层复制”操作。


Object 类本身不实现接口Cloneable,所以在类为 Object 的对象上调用 clone 方法将会导致在运行时抛出异常。


将以上内容进行总结,得出:


1、实现Cloneable接口。


2、重载clone()方法。


3、实现clone()方法时通过super.clone();调用Object实现的clone()方法来得到该对象的副本。


接着我们来看看clone()方法的两种克隆方式:


  克隆的对象:

public class CloneObject implements Serializable{
	private String name ;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}	
}

(1)浅度克隆:

public class SimpleClone implements Cloneable ,Serializable {	

    public CloneObject cloneObject = null;
	
	
	public SimpleClone(CloneObject cloneObject) {
		this.cloneObject = cloneObject;
	}

	public Object clone() {
		SimpleClone newSimpleClone =  null;
		try {
			newSimpleClone = (SimpleClone)super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return newSimpleClone;
	}
}


浅度克隆测试:

public class TestClone {
	
	public static void main(String[] arg) {
		CloneObject obj1 = new CloneObject();
		obj1.setName("cloneOne");
		CloneObject obj2 = new CloneObject();
		obj2.setName("cloneTwo");
		
		SimpleClone simpleClone1 = new SimpleClone(obj1);
		SimpleClone simpleClone2 = new SimpleClone(obj2);

		simpleClone2 = (SimpleClone)simpleClone1.clone();
	
		simpleClone2.cloneObject.setName("cloneThree");
		
		System.out.println(simpleClone1.cloneObject.getName());
		System.out.println(simpleClone2.cloneObject.getName());
	}
	
}
测试结果:

cloneThree

cloneThree


以上程序创建了两个对象obj1和obj2,并分别为name赋值“cloneOne”和“cloneTwo”,然后分别赋值给定义的两个


实现浅度克隆的类。我们看到以上程序为simpleClone1进行了克隆,并将克隆后的对象赋值给simpleClone2,之后


再对simpleClone进行重新赋值。最后我们看输出的结果,发现,simpleClone1.cloneObject.getName是随着


simpleClone2改变而改变,也就是说浅度克隆仅仅克隆了该对象的所有Field值,并没有对引用类型的Field值所引用


的对象进行克隆,实际上克隆的对象指向的还是同一个块内存地址。


(2)深度克隆:

public class DepthClone {
	public  final static Object objectCopy(Object oldObj) {
		Object newObj = null;	
		try {
			ByteArrayOutputStream bo = new ByteArrayOutputStream();
			ObjectOutputStream oo = new ObjectOutputStream(bo);
			oo.writeObject(oldObj);
			ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
			ObjectInputStream oi= new ObjectInputStream(bi);
			newObj = oi.readObject();
		} catch (IOException e) {
			e.printStackTrace();
		}catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
		return newObj;
	}
}

深度克隆测试:

public class TestClone {
	
	public static void main(String[] arg) {
		CloneObject obj1 = new CloneObject();
		obj1.setName("cloneOne");
		CloneObject obj2 = new CloneObject();
		obj2.setName("cloneTwo");
		
		SimpleClone simpleClone1 = new SimpleClone(obj1);
		SimpleClone simpleClone2 = new SimpleClone(obj2);
		
		simpleClone2 = (SimpleClone)DepthClone.objectCopy(simpleClone1);
		simpleClone2.cloneObject.setName("cloneThree");
		
		System.out.println(simpleClone1.cloneObject.getName());
		System.out.println(simpleClone2.cloneObject.getName());
	}
	
}

测试结果:

cloneOne

cloneThree

以上程序通过Java的对象序列化机制,将对象的状态转换成字节流,接着通过这些值再生成新的对象,最后我们


发现,simpleClone1.cloneObject.getName是不随着simpleClone2改变而改变,也就是说simpleClone1


和simpleClone2是被存在两个不同内存中。在使用 Java的序列化时,值得注意的是,如果这个类做了改动,然后


重新编译,那么这是反序列化刚才的对象就会产生异常,这时可以通过添加serialVersionUID属性来解决。





转载请注明出处:http://blog.csdn.net/hai_qing_xu_kong/article/details/43908709    情绪控_ 


的 








郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。