4

我在Java中有这段代码。

public class CloneTest implements Cloneable{
    String name;
    int marks;
    public CloneTest(String s, int i) {
        name = s;
        marks = i;
    }

    public void setName(String s) {
        name = s;
    }

    public void setMarks(int i) {
        marks = i;
    }

    @Override
    public Object clone() {
        return new CloneTest(this.name, this.marks);
    }
}

我已经创建了这个类的一个对象,然后克隆了它。现在,当我更改name一个对象中的值时,另一个对象中名称的值保持不变。这里奇怪的是在构造函数中,我只是使用了一个简单的引用 for name,而不是创建一个新String的 for name。现在,由于Strings 是引用类型,我希望String克隆中的 也可以更改。谁能告诉我发生了什么事?提前致谢!

编辑

代码测试

CloneTest real = new CloneTest("Molly", 22);
CloneTest clone = real.clone();
real.setName("Dolly");

我使用 BlueJ 的“检查变量”功能来检查值。

4

5 回答 5

4

假设这original是原始 CloneTest 对象的名称,并且cloned是您original使用该clone()方法创建的克隆对象。

这就是发生的事情:
1. 你的cloned.nameoriginal.name指向同一个对象,在这种情况下是一个字符串。
2. 然后你让你original.name指向一个不同的字符串对象(“Dolly”)。当您将新的 String 对象(“Dolly”)分配给引用时,就会发生这种情况original.name
3. 但是,cloned.name仍然指向第一个 String 对象(“Dolly”)。

因此,cloned.name仍然打印第一个 String 对象。

现在,如果您能够在不重新分配引用的情况下更改 String 对象的内容,那么更改clone.name将反映在original.name. 但是对于字符串对象,由于字符串的不变性,这是不可能的。但是,您可以使用可以说是可变字符串的StringBuffers来反映从cloneto的变化。看看这个示例代码:https ://gist.github.com/VijayKrishna/5967668original

于 2013-07-10T15:01:36.603 回答
2

类的每个实例对对象都有不同的引用。您只是在更改参考而不是修改对象。如果您将字符串放在某个持有人对象中,然后克隆它并在持有人内设置字符串(不是持有人引用,而是持有人内的字符串引用),那么您将在两个克隆中进行更改

于 2013-07-10T15:05:06.730 回答
0

通过查看哈希码来获得更好的清晰度以及@vijay 的答案。

    CloneTest real = new CloneTest("Molly", 22);
    CloneTest clone = (CloneTest) real.clone();
    int h1=real.name.hashCode();
    int h2=clone.name.hashCode();
    System.out.println("h1 "  + h1  + " h2 " + h2); // same
    real.setName("sak");
    h1=real.name.hashCode();
    h2=clone.name.hashCode();
    System.out.println("h1 "  + h1  + " h2 " + h2); //different

输出 :

 h1 74525175 h2 74525175
 h1 113629 h2 74525175
于 2013-07-10T15:31:09.753 回答
0

所以你是说你正在做类似的事情:

 public void testSomeMethod() {

      CloneTest a = new CloneTest("a", 1);

      CloneTest b = (CloneTest) a.clone();

      a.setName("b");

      assertFalse(b.name.equals(a.name));
      assertEquals("b", a.name);
      assertEquals("a", b.name);  
  }

?

如果是这样,那么所有这些断言都应该通过。您的 clone 方法中有引用类型,当最初克隆时,它们引用同一个对象。但是 setName("...") 改变了实例指向的值,而不是被引用对象的值。

于 2013-07-10T15:20:36.857 回答
0
package com.test;
class Manager implements Cloneable
{
String firstName;
String lastName;
int age;
public Manager(String fname,String lname,int a)
{
    this.firstName=fname;
    this.lastName=lname;
    this.age=a;
}
public String getFirstName() {
    return firstName;
}
public void setFirstName(String firstName) {
    this.firstName = firstName;
}
public String getLastName() {
    return lastName;
}
public void setLastName(String lastName) {
    this.lastName = lastName;
}
public int getAge() {
    return age;
}
public void setAge(int age) {
    this.age = age;
}
@Override
protected Object clone() throws CloneNotSupportedException {
    // TODO Auto-generated method stub
    return super.clone();
}

}

public class TestCloning {
public static void main(String[] args) throws CloneNotSupportedException {
    Manager m1=new Manager("Sadik","Tahir",26);
    Manager m_clone=(Manager)m1.clone();
    Manager m2=m1;
    System.out.println("M1 Details:::");
    System.out.println("Fisrt Name:"+m1.getFirstName()+",LastName:"+m1.getLastName()+",Age:"+m1.getAge());
    System.out.println("Hashcode:"+m1.hashCode());
    System.out.println("M_Clone Details:::");
    System.out.println("Fisrt Name:"+m_clone.getFirstName()+",LastName:"+m_clone.getLastName()+",Age:"+m_clone.getAge());
    System.out.println("Hashcode:"+m_clone.hashCode());
    System.out.println("M2 Details:::");
    System.out.println("Fisrt Name:"+m2.getFirstName()+",LastName:"+m2.getLastName()+",Age:"+m2.getAge());
    System.out.println("Hashcode:"+m2.hashCode());
    m1.setFirstName("Afreen");
    m1.setLastName("Khan");
    m1.setAge(25);
    System.out.println("M1 Details:::");
    System.out.println("Fisrt Name:"+m1.getFirstName()+",LastName:"+m1.getLastName()+",Age:"+m1.getAge());
    System.out.println("Hashcode:"+m1.hashCode());
    System.out.println("M_Clone Details:::");
    System.out.println("Fisrt Name:"+m_clone.getFirstName()+",LastName:"+m_clone.getLastName()+",Age:"+m_clone.getAge());
    System.out.println("Hashcode:"+m_clone.hashCode());
    System.out.println("M2 Details:::");
    System.out.println("Fisrt Name:"+m2.getFirstName()+",LastName:"+m2.getLastName()+",Age:"+m2.getAge());
    System.out.println("Hashcode:"+m2.hashCode());
}

}

于 2015-03-24T13:31:35.203 回答