1.clone()即对象所占"内存块"的复制;
2.因为改变的是基本类型字段的副本;
3.引用即指向对象的"指针",指针再怎么复制都是指向同一个对象;
4.一定要实现Cloneable//抛砖引玉,闪先
2.因为改变的是基本类型字段的副本;
3.引用即指向对象的"指针",指针再怎么复制都是指向同一个对象;
4.一定要实现Cloneable//抛砖引玉,闪先
解决方案 »
- 高手来看看,关于类的执行顺序问题
- 关于java中的打包命令Main-Class和Class-path的用法
- 各位大虾们,快过来帮小弟一把!!!急用的!!!!
- 郑重声明:最好的java ide是idea,不是eclipse.
- 如何只去掉字符串尾部的空格(半角,全角),前面的空格要保留,即不能用trim()方法。类似oracle中的rtrim()
- 请问各位高手,怎么查看我的java虚拟机内存大小?
- sql语句
- java中如何访问活动目录?
- 斑竹请进,大家也进来投票
- 一个SQL语句如何用程序判断它的列数??只查询一个表可以自动取出列数,而象下面的语句...
- 严正声明:对《程序员大本营2001Java版》不满意的请来签名抗议!!!
- 带下划线的类,是不是有什么特指的意思呀,比如_documentHandler,没有定义也能用吗?
1. Java的对象存储在一个连续区域里面
2. clone()的时候,将这个区域的内容不加区分拷贝到另外一个区域
是不是这样子呢?
2.Note that all arrays are considered to implement the interface Cloneable.
也就是说数组都被实现了Cloneable接口了?3."shallow copy"浅复制和"deep copy"深复制怎么理解和区别啊?
为什么x为object的实例时,x.clone()!=x 是true呢?按道理应该相等嘛克隆是制作一个对象的拷贝,
对象的==,!=的比较是比较对象的句柄,不是比较其值。因为克隆生成一个新的对象,所以他们的存储地址不一样,即句柄不同,所以
x为object的实例时,x.clone()!=x 是true
But the reference type just clone the same object's reference. Therefore when you make a change in the data member object, the original and the clone will be both changed.
翻译一下:但引用类型仅仅克隆了这同一个对象的引用。因此,当你修改这个对象中的一个数据成员时,原始的和克隆的数据成员都会被改变。
这么看来你所说的“克隆生成一个新的对象,所以他们的存储地址不一样,即句柄不同”不是不成立了?
理解有误,这里的reference是成员变量,复制时新clone的对象和被clone的对象里的这个成员变量的是相同,即两个reference指到了一个对象(不是clone和被clone的对象)上。这和c++里的shallow copy constructor一样,对指针类型只是简单的按值复制,所以出问题。
"shallow copy"实际上只是简单的创建了当前对象的一个拷贝(即将当前对象作为一个二进制的数据块复制到一个新的内存块中),对于改对象中的reference variable只复制了它的值而不是所指向的对象,因此在使用"shallow copy"的新拷贝中修改reference variable所指的对象会影响到原来被clone的对象。
而"deep copy"则可以避免这种情况的发生。它不但创建了当前对象的一个拷贝,而且还复制了当前对象中可能有的(注意:此时的reference variable值reference variable已经与原来的不一样了)。当然,这不算完,reference variable所指向的对象中可能也包含了reference variable,同样也要对其进行"deep copy"。
打个比方来说:
这有点象复制一个网页到自己的机子上,但是"shallow copy"只复制了当前页面,它上面链接得页面并没有保存下来,而"deep copy"则不然,它将所有被链接的页面都复制了下来(当然了,不仅仅只是复制一层而已),这就有点像是扒网站了,呵呵。
class XXX
{
int i=1;
boolean b=true;
float f=3.3f;
}
XXX x=new XXX();
这样初始化了一个XXX类的对象x,x应该表示的是整个对象内容(一个连续的内存块包括x.i,x.b,x.f)的首地址吧,
然后x.clone();那么这个x.clone()的值究竟表示什么呢?也是表示x对象所占的内存块的首地址吗?
如果这么理解,x.clone()=x不是要成立了吗?
又糊涂了.....你们看我的认识究竟是哪个地方有问题啊
public class CloneTest
{
public static class MyCloneable
implements Cloneable
{
public int i;
public StringBuffer s;
public void pr()
{
System.out.println( "i=" + i + ", s=" + s.toString() );
}
public Object clone()
throws CloneNotSupportedException, OutOfMemoryError
{
return super.clone();
}
}
public static void main( String args[] )
throws Exception
{
StringBuffer str = new StringBuffer( "AAA" );
MyCloneable origin, cloned;
origin = new MyCloneable();
origin.i = 10;
origin.s = str;
cloned = (MyCloneable)origin.clone();
System.out.println( "Origin: " );
origin.pr();
System.out.println( "Cloned: " );
cloned.pr();
cloned.s.append( "BBB" );
System.out.println( "Cloned modified: " );
cloned.pr();
System.out.println( "Origin also modified: " );
origin.pr();
}
}
//Results
Origin:
i=10, s=AAA
Cloned:
i=10, s=AAA
Cloned modified:
i=10, s=AAABBB
Origin also modified:
i=10, s=AAABBB
举个例子
class XXX
{
int i=1;
boolean b=true;
float f=3.3f;
}
XXX x=new XXX();
这样初始化了一个XXX类的对象x,x应该表示的是整个对象内容(一个连续的内存块包括x.i,x.b,x.f)的首地址吧,
然后x.clone();那么这个x.clone()的值究竟表示什么呢?也是表示x对象所占的内存块的首地址吗?
如果这么理解,x.clone()=x不是要成立了吗?
你们看我的认识究竟是哪个地方有问题啊
什么例子中的x.clone()得到一个新的对象句柄,也就是说它在内存里头新开了一块,然后把x中值复制到新内存块中,意思就是在内存中实现copy,所以
x.clone()!=x
由于你的例子中类成员变量都是基本类型,所以算是一个deep copy。
如果你的类A中有未实现克隆的类成员变量,则A.clone是一个"shallow copy",若要把类A变成一个可以deep copy的时候,
你必须让A中所有未实现克隆的类成员变量的类也实现克隆。
1.你楼上的那段我的话究竟错在哪里?2.举个例子:类中有未实现克隆的类成员变量,则类.clone是个浅copy
// The clone() operation works for only a few
// items in the standard Java library.
import java.util.*;class Int {
private int i;
public Int(int ii) { i = ii; }
public void increment() { i++; }
public String toString() {
return Integer.toString(i);
}
}public class Cloning {
public static void main(String[] args) {
Vector v = new Vector();
for(int i = 0; i < 10; i++ )
v.addElement(new Int(i));
System.out.println("v: " + v);
Vector v2 = (Vector)v.clone();
// Increment all v2's elements:
for(Enumeration e = v2.elements();
e.hasMoreElements(); )
((Int)e.nextElement()).increment();
// See if it changed v's elements:
System.out.println("v: " + v);
}
} ///:~clone()方法产生了一个Object,后者必须立即重新造型为正确类型。这个例子指出Vector的clone()方法不能自动尝试克隆Vector内包含的每个对象——由于别名问题,老的Vector和克隆的Vector都包含了相同的对象。我们通常把这种情况叫作“简单复制”或者“浅层复制”,因为它只复制了一个对象的“表面”部分。实际对象除包含这个“表面”以外,还包括句柄指向的所有对象,以及那些对象又指向的其他所有对象,由此类推。这便是“对象网”或“对象关系网”的由来。若能复制下所有这张网,便叫作“全面复制”或者“深层复制”。
内部类有如下属性:
类名称只能用在定义过的范围中,除非用在限定的名称中。内部类的名称必须与所嵌套的类不同。
......
被自动地声明为static的内部类成为顶层类。这些内部类失去了在本地范围和其它内部类中使用数据或变量的能力。
内部类不能声明任何static成员;只有顶层类可以声明static成员。因此,一个需求static成员的内部类必须使用来自顶层类的成员。
--- http://www.csdn.net/Expert/topic/419/419171.shtm本来我是没有加static,但是这样在new的时候出错
CloneTest.java:24: non-static variable this cannot be referenced from a static c
ontext
origin = new MyCloneable();
^
1 error
也就是说这样new出来的this是不能够在static的main里面使用的。
参考其它类似错误(比如在static方法里面引用普通的变量)的意思,再对照上面的话,就知道原因了。
在没有static的情况下,MyCloneable是一个内部类,它只能够在这个类的范围内使用,这和普通变量一样,而static方法本质上并不是属于这个类的范围之内的,因此它只能够new顶级类,只有真正的CloneTest的方法才可以在MyCloneable不使用static修饰的时候去new它。
举个例子
class XXX
{
int i=1;
boolean b=true;
float f=3.3f;
}
XXX x=new XXX();
这样初始化了一个XXX类的对象x,x应该表示的是整个对象内容(一个连续的内存块包括x.i,x.b,x.f)的首地址吧,
然后x.clone();那么这个x.clone()的值究竟表示什么呢?也是表示x对象所占的内存块的首地址吗?
如果这么理解,x.clone()=x不是要成立了吗?
你们看我的认识究竟是哪个地方有问题啊 ]
clone是有一点复杂的,大概是这样的:
XXX x=new XXX();
这是如果你想要clone这个x的话,你必须自己实现这个XXX:class XXX implements Cloneable{
int i=1;
boolean b=true;
float f=3.3f; public Object clone(){
XXX y=new XXX();
y.i=i;
y.b=b;
y.f=f;
return y;
} public boolean equals(Object o){
if(!(o instanceof XXX)) return false;
if((((XXX)o).i)==i && (((XXX)o).b)==b && (((XXX)o).f)==f) return true;
return false;
}
}public class Test{
public static void main(String[] args){
XXX x0=new XXX(); XXX x1=(XXX)x0.clone();
System.out.println(x0.hashCode()+" "+x1.hashCode());
System.out.println(x1==x0);
System.out.println(x0.getClass()+" "+x1.getClass());
System.out.println(x0.equals(x1));
}
}
1.对于对象中的基本数据类型的成员变量,可以进行值的复制,这样就有了两个拷贝.
2.对于复合类的对象(即包含其他类作为成员变量),它的非基本类型的成员变量所在的内存地址仅仅保存的是这个对象成员的首地址,所以复制的也仅仅是对象成员的首地址,所以说the default implementation of clone() is a shallow clone().如[hahaha88(忧郁的眼神,稀嘘的胡子喳)]所说的要想将这个shallow clone()变成deep clone(),就要自己实现.
就象c++中的将两个相同类的对象进行赋值时,如果,类中包含了指针类型的成员变量,那么仅仅复制指针中的内容,即两个指针指向了相同的地址,这是仅仅个类比,不是十分准确.不知我理解的是否准确,请高手指点.
[看了你的程序,我觉得是不是说实现cloneable接口就一定要覆盖equals方法啊?]这个问题略为复杂一点:
- 首先一个正确的clone实现必须满足下列条件:
1 x.clone() != x will be true
2 x.clone().getClass() == x.getClass()will be true
3 super.clone()被调用了
4 x.clone().equals(x) will be true(一般是这样,但不绝对,取决于你)
5 根据具体要求,决定是否/如何override Object.hashCode方法。 - 因为java.lang.Object的clone()方法是protected的,所以如果你想要让你的类
可以被clone,你首先必须override这个clone方法,并且你的实现必须满足
x!=x.clone()这个条件,即:如下实现是错的:
class MyClass{
public void clone(){
super.clone();
return this;
}
} 所以,一个正确的对于Object.clone()的override不会返回指向x的同一地址,
你必须开出一个新的内存区域,这一点是由x!=c.clone()这个要求(不是语法限制)
来保证的,否则如果返回同意内存地址,clone就没有意义了。- 现在我们已经知道,必须override clone()方法,那么是否必须要override equals方法?
不一定。
java.lang.Object对于equals的缺省实现是:
public boolean equals(Object obj) {
return (this == obj);
}
我们已经保证 x.clone() != x 了,所以如果你不override equals方法,则equals方法
返回false。所以如果希望x.clone().equals(x),那么你必须override equals(...)
方法,以保证 x.clone().equals(x)。 一般来说我们要保证这一点,但这取决于我们将要
怎么样用这个被我们clone出来的对象,许多操作(比如涉及到java.util.HashTable的
操作),将要用到equals。你要根据你的需要来决定如何处理equals。一般来说要保证
x.clone().equals(x)。EJB里有关于对equals的要求,具体我忘了,嘻嘻。 - 同样根据具体要求,决定是否/如何override Object.hashCode方法。 hashCode
和clone()在某些操作中是有关系的,理由同上(equals). - 在你override clone()方法时,最好/必须调用super.clone(),这是一个好习惯。
条件不是绝对的,但一般做好保证。Creates and returns a copy of this object. The precise meaning of "copy" may depend on the class of the object. The general intent is that, for any object x, the expression:
x.clone() != xwill be true, and that the expression:
x.clone().getClass() == x.getClass()will be true, but these are not absolute requirements. While it is typically the case that:
x.clone().equals(x)will be true, this is not an absolute requirement. Copying an object will typically entail creating a new instance of its class, but it also may require copying of internal data structures as well. No constructors are called.
The method clone for class Object performs a specific cloning operation. First, if the class of this object does not implement the interface Cloneable, then a CloneNotSupportedException is thrown. Note that all arrays are considered to implement the interface Cloneable. Otherwise, this method creates a new instance of the class of this object and initializes all its fields with exactly the contents of the corresponding fields of this object, as if by assignment; the contents of the fields are not themselves cloned. Thus, this method performs a "shallow copy" of this object, not a "deep copy" operation. The class Object does not itself implement the interface Cloneable, so calling the clone method on an object whose class is Object will result in throwing an exception at run time. The clone method is implemented by the class Object as a convenient, general utility for subclasses that implement the interface Cloneable, possibly also overriding the clone method, in which case the overriding definition can refer to this utility definition by the call: super.clone()
Patrick_DK
<java核心技术>有关于clone()的图解,对你不知道是否有帮助。