- 浏览: 898028 次
- 性别:
- 来自: 武汉
文章分类
最新评论
-
小宇宙_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 6005全文转载:http://www.iteye ... -
【JDK优化】java.util.Arrays的排序研究
2010-05-12 21:06 9193作者题记:JDK中有很多算法具有优化的闪光点,值得好好研究。 ... -
【JDK优化】 Integer 自动打包机制的优化
2010-03-12 19:14 4203我们首先来看一段代码: Integer i=100; In ... -
【总结】Java与字符编码问题详谈
2009-12-30 09:11 9428一、字符集和字符编码方式 计算机只懂得0/1两种信号 ... -
【解惑】 正确理解线程等待和释放(wait/notify)
2009-12-29 13:40 19771对于初学者来说,下面这个例子是一个非常常见的错误。 /** ... -
【解惑】JVM如何理解Java泛型类
2009-12-16 11:08 12379//泛型代码 public class Pair<T& ... -
【解惑】正确的理解this 和 super
2009-12-05 09:46 4474转载: 《无聊 ... -
【解惑】真正理解了protected的作用范围
2009-11-21 18:00 5095一提到访问控 ... -
【总结】String in Java
2009-11-21 17:52 10986作者:每次上网冲杯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 1890问题提出: 有两个类Manager和Em ... -
【总结】java命令解析以及编译器,虚拟机如何定位类
2009-11-01 16:25 5824学Java有些日子了,一直都使用IDE来写程序。这 ... -
【解惑】剖析float型的内存存储和精度丢失问题
2009-10-26 15:10 16087问题提出:12.0f-11.9f=0.10 ... -
【解惑】领略内部类的“内部”
2009-10-19 15:38 3599内部类有两种情况: (1) 在类中定义一个类(私有内部类 ... -
【解惑】深入jar包:从jar包中读取资源文件
2009-10-08 21:13 65950我们常常在代码中读取一些资源文件(比如图片,音乐,文 ... -
【解惑】理解java枚举类型
2009-09-26 09:37 3427枚举类型是JDK5.0的新特征。Sun引进了一个全新的关键字e ... -
编写自己的equals方法
2009-09-20 14:18 129在我的《令人头疼的"相等"关 ...
相关推荐
java 解惑 java 解惑 java 解惑 java 解惑 java 解惑 java 解惑
"solve65p"可能代表这本书包含65个问题或主题,每个都深入浅出地进行了讲解,旨在解决初学者在编程实践中可能遇到的常见问题。 Java是一种广泛使用的面向对象的编程语言,由Sun Microsystems(现已被Oracle公司收购...
本书深入浅出地探讨了Java语言的核心概念、常见疑惑以及最佳实践,旨在使开发者能够编写出更稳定、更高效的代码。 Java解惑部分涵盖了诸多主题,包括但不限于: 1. **内存管理**:Java的垃圾回收机制是其一大特色...
在《SQL解惑 第二版》中,作者深入浅出地讲解了SQL的基础概念,如SELECT语句、JOIN操作、子查询、聚合函数、排序与分组等,并通过具体实例让读者能更好地理解和应用这些知识。 1. SELECT语句:这是SQL中最基础的...
SQL解惑解惑,意味着我们将深入探讨SQL的常见问题、概念以及解决策略。在这个过程中,我们不仅要理解SQL的基本语法,还要掌握如何有效地查询、更新和管理数据。 首先,让我们从SQL的基础开始。SQL分为四大主要部分...
IT 学生解惑经典指导书 IT 学生解惑经典指导书 IT 学生解惑经典指导书 IT 学生解惑经典指导书 IT 学生解惑经典指导书 IT 学生解惑经典指导书 IT 学生解惑经典指导书 IT 学生解惑经典指导书
"java解惑" PDF版本
《IT学生解惑真经》是一本专门为在IT领域学习和探索的学生们量身打造的知识宝典。这本书的目的是帮助那些在信息技术世界中迷失方向、渴望深入理解和掌握核心技术的学子们,提供一套全面且实用的学习指南。书中的内容...
《IT解惑》是一部综合性的资源集合,包含了《IT学生解惑真经》、《程序员羊皮卷》和《高质量C编程指南》三部分,旨在为计算机科学与技术的学习者和未来的职业程序员提供全面的指导和建议。这些文档分别关注了IT学生...
文档《java解惑 PDF版》中列举了95个这样的谜题,每个谜题都旨在帮助开发者理解并纠正一些常见的错误理解。以下是根据提供的部分内容解析的几个相关知识点。 ### 表达式谜题与取余操作符(%)的行为 在Java中,...
《C语言解惑》是一本针对C语言编程学习者的进阶书籍,旨在帮助读者从错误分析的角度提高编程技能...通过深入浅出的讲解和丰富的案例分析,本书能够帮助读者在遇到编程难题时找到解决的思路和方法,提高编程效率和质量。
本书通过丰富的实例和深入浅出的讲解,让读者能够快速掌握C语言的核心概念和技术要点。 #### 二、核心知识点详解 ##### 1. 基础语法与数据类型 - **变量声明与初始化**:在C语言中,变量必须先声明后使用。例如,`...
这本书深入浅出地讲解了IT领域的基础知识,同时涵盖了现代信息技术的发展趋势和关键技能,为初涉IT行业的学生提供了宝贵的指导。 首先,书中可能涉及的基础知识部分包括计算机系统结构,从硬件到软件的全面理解。这...
《JAVA解惑》这本书主要针对Java编程中遇到的各种常见问题和困惑进行了解答,旨在帮助开发者深入理解Java语言,提高编程技巧。以下是一些关键的知识点解析: 1. **异常处理**:Java中的异常处理是通过try-catch-...
《Java解惑》 布洛克 著;陈昊鹏 译 扫描清晰带目录,仅供参阅,请支持正版
讲述如何在程序中避免程序缺陷和程序陷阱的,解惑的过程中,介绍了一些Java编程语言中许多不易被掌握的知识点,其阅读价值非常高,适合具有Java知识的学习者和有编程经验的Java程序员阅读。
"Java解惑"这个主题,显然旨在帮助开发者解决他们在学习和实践中遇到的问题。在Java的世界里,疑惑可能涵盖语法、类库、框架、并发、内存管理等多个方面。下面,我们将深入探讨一些常见的Java解惑知识点。 1. **...
这本书深入浅出地讲解了Java语言的核心概念和实战技巧,为读者提供了全面而详尽的解答。 首先,书中详细阐述了Java的基础知识,包括Java语法、类与对象、封装、继承和多态等面向对象编程的基本原理。这些内容是理解...
### IT学生解惑真经——助你明确方向与规划 #### 大学计算机课程学习路线 对于计算机相关专业的大学低年级学生而言,《精典IT学生解惑真经》中的“大学计算机课程学习路线”章节提供了非常实用的学习指南。这一...