- 浏览: 888604 次
- 性别:
- 来自: 武汉
文章分类
最新评论
-
小宇宙_WZY:
膜拜一下大神,解决了我一个大问题,非常感谢 orz
【解惑】深入jar包:从jar包中读取资源文件 -
JKL852qaz:
感谢,遇到相同的问题!
【解惑】深入jar包:从jar包中读取资源文件 -
lgh1992314:
为什么java中调用final方法是用invokevirtua ...
【解惑】Java动态绑定机制的内幕 -
鲁曼1991:
说的都有道理,protected只能被同一级包的类所调用
【解惑】真正理解了protected的作用范围 -
鲁曼1991:
...
【总结】String in Java
★ Java对象赋值
Employee e1=new Employee("李"); //Employee是一个自定义类 Employee e2=e1; //赋值对象 e2.setName("王");//改变对象e2的名字 System.out.println(e1.getName()); //打印e1的结果: 王 Employee e1=new Employee("李"); //Employee是一个自定义类 Employee e2=e1; //赋值对象 e2.setName("王");//改变对象e2的名字 System.out.println(e1.getName()); //打印e1的结果: 王
这就是Java的对象赋值,改变e2的内容竟然会影响e1的内容。原因很简单,就是e1和e2这两个对象引用都指向了堆中同一个Employee类对象的内容。也就是说: Java的对象赋值的是引用(相当于C的指针)。如何让e1,e2成为内容相同的两个完全不同的对象呢,这就需要用到Java的对象克隆机制(将e2复制成e1的一个独立副本)。
★ Java对clone的支持
(1) 继承Object的clone方法的疑问?
有一点我们很清楚,Java的万类之祖Object中有一个clone()方法:
protected native Object clone() throws CloneNotSupportedException
既然这个方法是protected的,显然是为了让子类能够使用。看看下面的代码:
//Employee类中没有clone方法,也没有实现Cloneable接口 Employee original=new Employee("John Public"); Employee copy=original.clone(); //wrong //Employee类中没有clone方法,也没有实现Cloneable接口 Employee original=new Employee("John Public"); Employee copy=original.clone(); //wrong
有人会提出这样的疑问:不是所有的类都是Object的子类吗?不是所有的子类都可以访问受保护的方法吗 ? 毫无疑问,这两句提问没有任何错误。但是有一点必须搞清楚:你是否正真理解protected的作用范围呢?《【Java语言】你是否真正理解了protected的作用范围呢?》 。
(2) Java支持克隆
既然如此,难道我们就没有办法在某一个类的作用域外部来克隆这个类了吗?
答案是否定的! 我们可以在任何一个类中重写clone方法,并升级它的访问作用域。事实上,使用的时候也就是这样做的!
首先我们必须在需要克隆的类上实现一个重要的接口——Cloneable接口。这种接口我们叫作标记接口(tagging interface) 。这种标记接口没有任何方法,唯一的作用就是作为一个标志,用来告诉JVM一个类是否具有某个特定的功能。
如此一来,我们只要定义一个具有 Clone 功能的类就可以了:
1. 在类的声明中加入“ implements Cloneable ”,标志该类有克隆功能;
2. 重载类 Object 的 clone() 方法,在该方法中调用 super.clone() :
class Employee implements Cloneable{ public Object clone() throws CloneNotSupportedException{//重载clone()方法 Employee cloned=(Employee)super.clone(); return cloned; } } class Employee implements Cloneable{ public Object clone() throws CloneNotSupportedException{//重载clone()方法 Employee cloned=(Employee)super.clone(); return cloned; } }
★ 深Clone和浅Clone
拷贝副本的问题并没有完全解决。clone技术并不是那么简单的。Object中的clone()方法是对具体类对象的各个域进行对应的赋值。如果具体类对象中还有子对象,这个问题就复杂了。
// 具备浅克隆的Employee类 class Employee implements Cloneable{ public String name=""; public Date hireDay=null; public Object clone(){ Employee cloned=(Employee)super.clone(); return cloned; } } Employee orignal=new Employee(); Employee copy=orignal.copy();
对于上面的代码,克隆以后orignal与copy中的hireDay指向的是同样的存储位置。也就是说当我们调用copy.hireDay.setTime()方法后,orignal中的hireDay也会发生改变。但String类(由于常量池的存储方式)和基本数据类型变量时不会改变的。这种对子对象克隆无效的方式我们叫做浅克隆 。
很多情况下,我们需要将对象中的所有域(包括子对象)都进行真正的克隆。要做到这种深克隆,我们必须在重载clone()方法时克隆子对象:
//具备深度克隆功能的Employee类 class Employee implement Cloneable{ public String name=""; private Date hireDay=null; public Object clone(){ Employee cloned=(Employee)super.clone(); //浅克隆 cloned.hireDay=(Date)hireDay.clone(); //克隆子对象 return cloned; } }
评论
import java.util.Date;
class Address implements Cloneable{
String city;
Address(String city){
this.city=city;
}
public String getCity() {
return city;
}
@Override
public String toString() {
return "Address [city=" + city + "]";
}
public void setCity(String city) {
this.city = city;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Employee implements Cloneable{
String name;
int salary;
Address addr;
Date hirDate;
public Employee(String name,int salary,Address city,Date hirDate){
this.name=name;
this.salary=salary;
this.addr=city;
this.hirDate=hirDate;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public Date getHirDate() {
return hirDate;
}
public void setHirDate(Date hirDate) {
this.hirDate = hirDate;
}
public void setSalary(int salary) {
this.salary = salary;
}
public Address getAddr() {
return addr;
}
public void setAddr(Address addr) {
this.addr = addr;
}
@Override
public String toString() {
return "Employee [addr=" + addr + ", hirDate=" + hirDate + ", name="
+ name + ", salary=" + salary + "]";
}
@Override
protected Object clone() throws CloneNotSupportedException {
Employee cloned=(Employee)super.clone();
return cloned;
}
public static void main(String[] args) throws CloneNotSupportedException{ //
Employee e1=new Employee("李",500,new Address("北京"),new Date()); //Employee是一个自定义类
Employee e2=e1; //赋值对象
e2.setName("王");//改变对象e2的名字
e2.setSalary(1000);
e2.setAddr(new Address("上海"));
e2.setHirDate(new Date(2007,7,1));
System.out.println("e1:"+e1); //打印e1的结果: 王
System.out.println("e2:"+e2); //打印e1的结果: 王
Employee e11=new Employee("李",500,new Address("北京"),new Date()); //Employee是一个自定义类
Employee e21=(Employee)e11.clone(); //赋值对象
e21.setName("王");//改变对象e2的名字
e21.setSalary(1000);
e21.setAddr(new Address("上海"));
e21.setHirDate(new Date(2007,7,1));
System.out.println("e11:"+e11); //打印e1的结果: 王
System.out.println("e21:"+e21); //打印e1的结果: 王
}
}
这段程序打印结果为:
e1:Employee [addr=Address [city=上海], hirDate=Thu Aug 01 00:00:00 CST 3907, name=王, salary=1000]
e2:Employee [addr=Address [city=上海], hirDate=Thu Aug 01 00:00:00 CST 3907, name=王, salary=1000]
e11:Employee [addr=Address [city=北京], hirDate=Thu Sep 29 19:58:57 CST 2011, name=李, salary=500]
e21:Employee [addr=Address [city=上海], hirDate=Thu Aug 01 00:00:00 CST 3907, name=王, salary=1000]
克隆也正常呀!
import java.util.Date;
class Address implements Cloneable{
String city;
Address(String city){
this.city=city;
}
public String getCity() {
return city;
}
@Override
public String toString() {
return "Address [city=" + city + "]";
}
public void setCity(String city) {
this.city = city;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Employee implements Cloneable{
String name;
int salary;
Address addr;
Date hirDate;
public Employee(String name,int salary,Address city,Date hirDate){
this.name=name;
this.salary=salary;
this.addr=city;
this.hirDate=hirDate;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public Date getHirDate() {
return hirDate;
}
public void setHirDate(Date hirDate) {
this.hirDate = hirDate;
}
public void setSalary(int salary) {
this.salary = salary;
}
public Address getAddr() {
return addr;
}
public void setAddr(Address addr) {
this.addr = addr;
}
@Override
public String toString() {
return "Employee [addr=" + addr + ", hirDate=" + hirDate + ", name="
+ name + ", salary=" + salary + "]";
}
@Override
protected Object clone() throws CloneNotSupportedException {
Employee cloned=(Employee)super.clone();
return cloned;
}
public static void main(String[] args) throws CloneNotSupportedException{ //
Employee e1=new Employee("李",500,new Address("北京"),new Date()); //Employee是一个自定义类
Employee e2=e1; //赋值对象
e2.setName("王");//改变对象e2的名字
e2.setSalary(1000);
e2.setAddr(new Address("上海"));
e2.setHirDate(new Date(2007,7,1));
System.out.println("e1:"+e1); //打印e1的结果: 王
System.out.println("e2:"+e2); //打印e1的结果: 王
Employee e11=new Employee("李",500,new Address("北京"),new Date()); //Employee是一个自定义类
Employee e21=(Employee)e11.clone(); //赋值对象
e21.setName("王");//改变对象e2的名字
e21.setSalary(1000);
e21.setAddr(new Address("上海"));
e21.setHirDate(new Date(2007,7,1));
System.out.println("e11:"+e11); //打印e1的结果: 王
System.out.println("e21:"+e21); //打印e1的结果: 王
}
}
这段程序打印结果为:
e1:Employee [addr=Address [city=上海], hirDate=Thu Aug 01 00:00:00 CST 3907, name=王, salary=1000]
e2:Employee [addr=Address [city=上海], hirDate=Thu Aug 01 00:00:00 CST 3907, name=王, salary=1000]
e11:Employee [addr=Address [city=北京], hirDate=Thu Sep 29 19:58:57 CST 2011, name=李, salary=500]
e21:Employee [addr=Address [city=上海], hirDate=Thu Aug 01 00:00:00 CST 3907, name=王, salary=1000]
克隆也正常呀!
那是因为你还没理解深克隆的含义。
通过浅克隆生成的对象和原对象,它们的实例对象引用其实指向同一对象。
而你并没有修改子对象,而是再new一个新对象,让子对象指向新的对象。
这样一来,克隆对象和原对象里相同的子对象就指向了不同的对象。
import java.util.Date;
class Address implements Cloneable{
String city;
Address(String city){
this.city=city;
}
public String getCity() {
return city;
}
@Override
public String toString() {
return "Address [city=" + city + "]";
}
public void setCity(String city) {
this.city = city;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Employee implements Cloneable{
String name;
int salary;
Address addr;
Date hirDate;
public Employee(String name,int salary,Address city,Date hirDate){
this.name=name;
this.salary=salary;
this.addr=city;
this.hirDate=hirDate;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public Date getHirDate() {
return hirDate;
}
public void setHirDate(Date hirDate) {
this.hirDate = hirDate;
}
public void setSalary(int salary) {
this.salary = salary;
}
public Address getAddr() {
return addr;
}
public void setAddr(Address addr) {
this.addr = addr;
}
@Override
public String toString() {
return "Employee [addr=" + addr + ", hirDate=" + hirDate + ", name="
+ name + ", salary=" + salary + "]";
}
@Override
protected Object clone() throws CloneNotSupportedException {
Employee cloned=(Employee)super.clone();
return cloned;
}
public static void main(String[] args) throws CloneNotSupportedException{ //
Employee e1=new Employee("李",500,new Address("北京"),new Date()); //Employee是一个自定义类
Employee e2=e1; //赋值对象
e2.setName("王");//改变对象e2的名字
e2.setSalary(1000);
e2.setAddr(new Address("上海"));
e2.setHirDate(new Date(2007,7,1));
System.out.println("e1:"+e1); //打印e1的结果: 王
System.out.println("e2:"+e2); //打印e1的结果: 王
Employee e11=new Employee("李",500,new Address("北京"),new Date()); //Employee是一个自定义类
Employee e21=(Employee)e11.clone(); //赋值对象
e21.setName("王");//改变对象e2的名字
e21.setSalary(1000);
e21.setAddr(new Address("上海"));
e21.setHirDate(new Date(2007,7,1));
System.out.println("e11:"+e11); //打印e1的结果: 王
System.out.println("e21:"+e21); //打印e1的结果: 王
}
}
这段程序打印结果为:
e1:Employee [addr=Address [city=上海], hirDate=Thu Aug 01 00:00:00 CST 3907, name=王, salary=1000]
e2:Employee [addr=Address [city=上海], hirDate=Thu Aug 01 00:00:00 CST 3907, name=王, salary=1000]
e11:Employee [addr=Address [city=北京], hirDate=Thu Sep 29 19:58:57 CST 2011, name=李, salary=500]
e21:Employee [addr=Address [city=上海], hirDate=Thu Aug 01 00:00:00 CST 3907, name=王, salary=1000]
克隆也正常呀!
http://www.iteye.com/topic/659877#1484197
深copy用对象串行化的方法吧
}
你知道现代计算机对这样一个循环需要多久时间吗?连毫秒都显示不出来的。
循环100000000大概281ms左右
你的new Date()是没有什么不太一样的。换个别的对象试试
import java.util.Date;
public class CloneTest implements Cloneable{
private String s ;
private Date d ;
public void setD(Date d) {
this.d = d;
}
public void setS(String s) {
this.s = s;
}
public String say(){
return s + d ;
}
public Object clone(){
CloneTest cloned = null ;
try {
cloned = (CloneTest)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return cloned;
}
public static void main(String[] args) {
CloneTest clone = new CloneTest();
clone.setS("ssssssssssss") ;
clone.setD(new Date());
for(int i =0;i<10000;i++){
}
System.out.println( clone.say());
CloneTest clone2 = (CloneTest) clone.clone();
clone2.setS("sss");
clone2.setD(new Date());
System.out.println(clone.say()) ;
System.out.println( clone2.say()) ;
}
}
哥,一分钟之内是跑得完i从0到10000的,而且不同是值引用的对象不同。clone.getD()==clone2.getD()是false的。
import java.util.Date;
public class CloneTest implements Cloneable{
private String s ;
private Date d ;
public void setD(Date d) {
this.d = d;
}
public void setS(String s) {
this.s = s;
}
public String say(){
return s + d ;
}
public Object clone(){
CloneTest cloned = null ;
try {
cloned = (CloneTest)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return cloned;
}
public static void main(String[] args) {
CloneTest clone = new CloneTest();
clone.setS("ssssssssssss") ;
clone.setD(new Date());
for(int i =0;i<10000;i++){
}
System.out.println( clone.say());
CloneTest clone2 = (CloneTest) clone.clone();
clone2.setS("sss");
clone2.setD(new Date());
System.out.println(clone.say()) ;
System.out.println( clone2.say()) ;
}
}
发表评论
-
NIO
2010-08-05 10:36 0在JDK1.4以前,I/O输入输出处理,我们把它称为旧 ... -
【总结】Java线程同步机制深刻阐述
2010-05-16 10:21 5937全文转载:http://www.iteye ... -
【JDK优化】java.util.Arrays的排序研究
2010-05-12 21:06 9116作者题记:JDK中有很多算法具有优化的闪光点,值得好好研究。 ... -
【JDK优化】 Integer 自动打包机制的优化
2010-03-12 19:14 4086我们首先来看一段代码: Integer i=100; In ... -
【总结】Java与字符编码问题详谈
2009-12-30 09:11 9351一、字符集和字符编码方式 计算机只懂得0/1两种信号 ... -
【解惑】 正确理解线程等待和释放(wait/notify)
2009-12-29 13:40 19659对于初学者来说,下面这个例子是一个非常常见的错误。 /** ... -
【解惑】JVM如何理解Java泛型类
2009-12-16 11:08 12233//泛型代码 public class Pair<T& ... -
【解惑】正确的理解this 和 super
2009-12-05 09:46 4418转载: 《无聊 ... -
【解惑】真正理解了protected的作用范围
2009-11-21 18:00 5008一提到访问控 ... -
【总结】String in Java
2009-11-21 17:52 10822作者:每次上网冲杯Java时,都能看到关于String无休无止 ... -
【解惑】真正理解了protected的作用范围
2009-11-16 17:11 585一提到访问控制符protected,即使是初学者 ... -
总结Java标准类库中类型相互转化的方法
2009-11-09 21:57 210组一: ☆ String → byte[ ... -
方法没覆盖住带来的烦恼
2009-11-05 09:18 100Object类是所有类的祖宗,它的equals方法比较的 ... -
【解惑】数组向上转型的陷阱
2009-11-03 11:44 1841问题提出: 有两个类Manager和Em ... -
【总结】java命令解析以及编译器,虚拟机如何定位类
2009-11-01 16:25 5754学Java有些日子了,一直都使用IDE来写程序。这 ... -
【解惑】剖析float型的内存存储和精度丢失问题
2009-10-26 15:10 15835问题提出:12.0f-11.9f=0.10 ... -
【解惑】领略内部类的“内部”
2009-10-19 15:38 3541内部类有两种情况: (1) 在类中定义一个类(私有内部类 ... -
【解惑】深入jar包:从jar包中读取资源文件
2009-10-08 21:13 65456我们常常在代码中读取一些资源文件(比如图片,音乐,文 ... -
【解惑】理解java枚举类型
2009-09-26 09:37 3358枚举类型是JDK5.0的新特征。Sun引进了一个全新的关键字e ... -
编写自己的equals方法
2009-09-20 14:18 129在我的《令人头疼的"相等"关 ...
相关推荐
java解惑java解惑java解惑java解惑java解惑java解惑
Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑
解惑SQL
Java解惑.pdf Java解惑.pdf Java解惑.pdf Java解惑.pdf
SQL解惑(第2版)
《Java解惑》《Java解惑》《Java解惑》《Java解惑》《Java解惑》《Java解惑》
JAVA解惑.pdf JAVA解惑.pdf JAVA解惑.pdf
Java解惑中文版 Java解惑 java健壮程序
EXCEL函数公式解惑专集EXCEL函数公式解惑专集
扫描完整版 解惑大数据 解惑大数据 解惑大数据 解惑大数据
IT 学生解惑经典指导书 IT 学生解惑经典指导书 IT 学生解惑经典指导书 IT 学生解惑经典指导书 IT 学生解惑经典指导书 IT 学生解惑经典指导书 IT 学生解惑经典指导书 IT 学生解惑经典指导书
C语言解惑中文版.pdf 扫描版
IT学生解惑真经
IT 学生解惑真经
JAVA面试题解惑系列合集 JAVA面试题解惑系列合集 JAVA面试题解惑系列合集
IT解惑,内容包括IT学生解惑真经、程序员羊皮卷、高质量c编程指南,其中涉及计算机专业学生的大学生活该如何度过,及求职的相关注意事项和C语言编程的一些经验。
"java解惑" PDF版本
C语言解惑。经典C语言解惑
JAVA解惑,你面包括一些java经典的问题。