使用clone( )和Cloneable接口
由Object类定义的绝大部分方法在本书其他部分讨论。而一个特别值得关注的方法是clone( )。clone( )方法创建调用它的对象的一个复制副本。只有那些实现Cloneable接口的类能被复制。
Cloneable接口没有定义成员。它通常用于指明被创建的一个允许对对象进行位复制(也就是对象副本)的类。如果试图用一个不支持Cloneable接口的类调用clone(
)方法,将引发一个CloneNotSupportedExcepti
on异常。当一个副本被创建时,并没有调用被复制对象的构造函数。副本仅仅是原对象的一个简单精确的拷贝。
复制是一个具有潜在危险的操作,因为它可能引起不是你所期望的副作用。例如,假如被复制的对象包含了一个称为obRef的引用变量,当副本创建时,副
本中的obRef如同原对象中的obRef一样引用相同的对象。如果副本改变了被obRef引用的对象的内容,那么对应的原对象也将被改变。这里是另一个
例子。如果一个对象打开一个I/O流并被复制,两个对象将可操作相同的流。而且,如果其中一个对象关闭了流,而另一个对象仍试图对I/O流进行写操作的
话,将导致错误。
由于复制可能引起问题,因此在Object内,clone(
)方法被说明为protected。这就意味着它必须或者被由实现Cloneable的类所定义的方法调用,或者必须被那些类显式重载以便它是公共的。让我们看关于下面每一种方法的例子。
下面的程序实现Cloneable接口并定义cloneTest( )方法,该方法在Object中调用clone(
)方法:
// Demonstrate the clone() method.
class TestClone implements Cloneable {
int a;
double b;
// This method calls Object's clone().
TestClone cloneTest() {
try {
// call clone in Object.
return (TestClone) super.clone();
} catch(CloneNotSupportedException e) {
System.out.println("Cloning not allowed.");
return this;
}
}
}
class CloneDemo {
public static void main(String args[]) {
TestClone x1 = new TestClone();
TestClone x2;
x1.a = 10;
x1.b = 20.98;
x2 = x1.cloneTest(); // clone x1
System.out.println("x1: " + x1.a + " " + x1.b);
System.out.println("x2: " + x2.a + " " + x2.b);
}
}
这里,方法cloneTest( )在Object中调用clone( )方法并且返回结果。注意由clone(
)方法返回的对象必须被强制转换成它的适当类型(TestClone)。
下面的例子重载clone(
)方法以便它能被其类外的程序所调用。为了完成这项功能,它的存取说明符必须是public,如下所示:
// Override the clone() method.
class TestClone implements Cloneable {
int a;
double b;
// clone() is now overridden and is public.
public Object clone() {
try {
// call clone in Object.
return super.clone();
} catch(CloneNotSupportedException e) {
System.out.println("Cloning not allowed.");
return this;
}
}
}
class CloneDemo2 {
public static void main(String args[]) {
TestClone x1 = new TestClone();
TestClone x2;
x1.a = 10;
x1.b = 20.98;
// here, clone() is called directly.
x2 = (TestClone) x1.clone();
System.out.println("x1: " + x1.a + " " + x1.b);
System.out.println("x2: " + x2.a + " " + x2.b);
}
}
由复制带来的副作用最初一般是比较难发现的。通常很容易想到的是类在复制时是很安全的,而实际却不是这样。一般在没有一个必须的原因的情况下,对任何类都不应该执行Cloneable。
浅复制和深复制来说一下,首先需要了解对象深、浅复制的概念:
深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。
此处,写一个深浅复制的例子:
public class Prototype implements Cloneable, Serializable {
- private static final long serialVersionUID = 1L;
- private String string;
- private SerializableObject obj;
- /* 浅复制 */
- public Object clone() throws CloneNotSupportedException {
- Prototype proto = (Prototype) super.clone();
- return proto;
- }
- /* 深复制 */
- public Object deepClone() throws IOException, ClassNotFoundException {
- /* 写入当前对象的二进制流 */
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- ObjectOutputStream oos = new ObjectOutputStream(bos);
- oos.writeObject(this);
- /* 读出二进制流产生的新对象 */
- ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
- ObjectInputStream ois = new ObjectInputStream(bis);
- return ois.readObject();
- }
- public String getString() {
- return string;
- }
- public void setString(String string) {
- this.string = string;
- }
- public SerializableObject getObj() {
- return obj;
- }
- public void setObj(SerializableObject obj) {
- this.obj = obj;
- }
- }
- class SerializableObject implements Serializable {
- private static final long serialVersionUID = 1L;
- }
使用clone( )和Cloneable接口的更多相关文章
- Cloneable接口和Object的clone()方法
为什么要克隆 为什么要使用克隆,这其实反映的是一个很现实的问题,假如我们有一个对象: public class SimpleObject implements Cloneable { private ...
- Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨
Java对象克隆(Clone)及Cloneable接口.Serializable接口的深入探讨 Part I 没啥好说的,直接开始Part II吧. Part II 谈到了对象的克隆,就不得不说为什么 ...
- (转)Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨
原文地址:http://blog.csdn.net/kenthong/article/details/5758884 Part I 没啥好说的,直接开始Part II吧. Part II 谈到了对象的 ...
- java开发——Cloneable接口、clone()方法和深浅拷贝
1.实现Cloneable接口表明该类的对象是允许克隆的. 2.允许克隆的意思是:可以调用clone()方法. 3.深拷贝还是浅拷贝,取决于如何重写Object的clone()方法. 4.原对象和克隆 ...
- Java 深拷贝、浅拷贝及Cloneable接口
Cloneable接口是一个空接口,仅用于标记对象,Cloneable接口里面是没有clone()方法,的clone()方法是Object类里面的方法!默认实现是一个Native方法 protecte ...
- java 的对象拷贝(有深浅拷贝两种方式,深拷贝实现的两种方式(逐层实现cloneable接口,序列化的方式来实现))
Java提高篇--对象克隆(复制)(转自:http://www.cnblogs.com/Qian123/p/5710533.html#_label0) 阅读目录 为什么要克隆? 如何实现克隆 浅克 ...
- java对象 深度克隆(不实现Cloneable接口)和浅度克隆
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt128 为什么需要克隆: 在实际编程过程中,我们常常要遇到这种情况:有一个对象 ...
- Java中的Cloneable接口理解
Cloneable接口是一个标记接口,也就是没有任何内容,定义如下: 这里分析一下这个接口的用法,clone方法是在Object种定义的,而且是protected型的,只有实现了这个接口,才可以在该类 ...
- java Comparable 和 Cloneable接口
Comparable接口定义了compareTo方法,用于比较对象. 例如,在JavaAPI中,Integer.BigInteger.String以及Date类定义如下 Cloneable接口 Clo ...
随机推荐
- CSS3随内容自动伸缩的背景
CSS3给我们带来一个非常实用的新属性:border-image,利用这个属性我们可以做出随着内容的增减自动伸缩的背景.废话不多说,看代码! HTML: <ol> <li>第一 ...
- IOS6学习笔记(二)
四.使用关联引用为分类添加数据 虽然不能在分类中创建实例变量,但是可以创建关联引用(associative reference).通过关联引用,你可以向任何对象中添加键-值(key-value)数据. ...
- Win10的分辨率问题
个人觉得win10扁平化的界面给人全新的感觉,但安装后,发现分辨率只有1280x720.1152x864.1024x768(推荐).800x600,不管调整哪一个,都觉得分辨率还是有问题,看起来字体. ...
- sql和access中截取字符串的区别
一向对数据库不熟悉,今天又遇到简单而又被忽略的问题——字符串的截取. 在Excel处理数据过程中,我们常用substring,left,mid,right来截取字符:在.NET编程中,我们常用subs ...
- .NET破解之百度网盘批量转存工具
在百度网盘上看到好的资源,总想转存到自己的网盘,加以整理.由于分享的规则原因,手动转存非常麻烦,于是百度批量转存工具.最先搜到的是小兵的百度云转存助手,无需注册,试用版用户一次只能操作10个,而捐助用 ...
- SharePoint 2013 点击"关注" 报错
现象: 点击"关注" 报错. 解决办法: 1.确保bin文件夹下的.dll版本与web.config一致. 2.设置user porfile权限. 2.重启iis 结果如下:
- linux网络流量实时监控工具之iptraf
这个工具还是很强大 linux网络流量实时监控工具之iptraf [我的Linux,让Linux更易用]IPTraf是一个网络监控工具,功能比nload更强大,可以监控所有的流量,IP流量,按协议分的 ...
- VC连接mysql数据库错误:libmysql.lib : fatal error LNK1113: invalid machine 解决方法
VC连接MySQL的配置过程在上一篇博文中,不过当你设置好,以为万事大吉的时候,运行却出现这个错误:libmysql.lib : fatal error LNK1113: invalid machin ...
- Python数据结构与算法--List和Dictionaries
Lists 当实现 list 的数据结构的时候Python 的设计者有很多的选择. 每一个选择都有可能影响着 list 操作执行的快慢. 当然他们也试图优化一些不常见的操作. 但是当权衡的时候,它们还 ...
- 学习android学习必备的java基础知识--四大内部类
学习android必备的java基础知识--四大内部类 今天学习android课程,因为我的主专业是JAVA,但是兴趣班却有这其他专业的同学,学习android 需要具备一些java的基础知识,因此就 ...