Java clone() 和 equals() 检查

Posted

技术标签:

【中文标题】Java clone() 和 equals() 检查【英文标题】:Java clone() and equals() check 【发布时间】:2014-11-06 11:32:55 【问题描述】:

对于下面的类,我知道c1.equals(c3) 返回 false,因为c1.clone() 创建了指向同一对象的不同引用。但是为什么carList1.equals(carList2) 返回true?为什么它与c1.equals(c3) 不同?非常感谢!

class Car implements Cloneable 
   private String plate;   
   private double maxSpeed;     
  public Car(String lp, double max) 
      license = lp;
      maxSpeed = max;
   
  public static void main(String[] args) throws Exception
      Car c1 = new Car("ABC123", 150.0);
      Car c2 = new Car("ABC123", 150.0);
      Car c3 = (Car) c1.clone();
      ArrayList<Car> carList1 = new ArrayList<Car>();
      carList1.add(c1);
      carList1.add(c2);
      ArrayList carList2 = (ArrayList) carList1.clone();
   

【问题讨论】:

【参考方案1】:

clone of ArrayList 执行浅拷贝,即它不会克隆 ArratList 中包含的元素,它只是复制引用。这就是 equals 返回 true 的原因,因为它不比较 ArrayList 对象的引用,而是比较列表中的元素。

公共对象克隆()

返回此 ArrayList 实例的浅表副本。 (要素 自己不会被复制。)

公共布尔等于(对象o)

比较指定对象与此列表是否相等。退货 当且仅当指定的对象也是一个列表时才为真,这两个列表 具有相同的大小,并且两者中所有对应的元素对 列表是相等的。 (两个元素 e1 和 e2 相等 if (e1==null ? e2==null : e1.equals(e2))。)换句话说,两个列表被定义为 如果它们以相同的顺序包含相同的元素,则它们相等。

另一方面,Car,假设你没有重写它的 equals 方法来比较成员,使用 Object::equals 的默认实现,它比较对象引用,因此克隆的 Car 不等于原作。

【讨论】:

此外,如果Car 有一个合理的equals() 实现,而不是依赖于从Object 继承的实现,那么c3.equals(c1) 也是如此。 但我认为对象的克隆也是浅拷贝?加上这里***.com/questions/1574960/…的这个问题,两个数组的equals()返回false。我真的很困惑。 @user3735871 对象的克隆是您必须自己实现的。它是否很浅也没关系,因为您没有覆盖 equals 方法。 @user3735871 不同之处在于ArrayList(或者更确切地说是它的祖先AbstractList确实覆盖了equals(),因此只有列表的内容很重要。 @user3735871 在您链接到的问题中,比较的对象是数组,而不是 ArrayLists。 ArrayList 会覆盖 Object 的 equals 方法,而 array 不会。这就是不同行为的原因。【参考方案2】:

ArrayList 没有equals() 方法。它扩展了AbstractList,它定义/实现了equals()clone() 只是复制引用,所以两个列表中的对象是相同的。 来自 oracle 文档:equals() 这样做:

比较指定对象与此列表是否相等。退货 当且仅当指定的对象也是一个列表时才为真,这两个列表 具有相同的大小,并且两者中所有对应的元素对 列表是相等的。 (两个元素 e1 和 e2 相等 if (e1==null ? e2==null : e1.equals(e2))。)换句话说,两个列表被定义为 如果它们以相同的顺序包含相同的元素,则它们是相等的。这 实现首先检查指定的对象是否是这个列表。如果 所以,它返回true;如果不是,它检查指定的对象是否是 列表。如果不是,则返回 false;如果是这样,它会遍历两个列表, 比较相应的元素对。如果有任何比较返回 false,此方法返回 false。如果任一迭代器用完 另一个之前的元素它返回false(因为列表是 长度不等);否则在迭代时返回true 完成。

【讨论】:

【参考方案3】:

这一切都取决于equals(...) 的实现。 clone() 函数不会复制所有内容,只要您不覆盖它(在 Clonable JavaDoc 中推荐)。

所以,你应该做两件事:

    覆盖clone() 覆盖equals()(以及hashCode()

【讨论】:

【参考方案4】:

您的Car 类尚未覆盖equals()。因此它仅通过对象标识来评估相等性,默认行为 - 与 == 运算符相同。

另一方面,ArrayList 已经覆盖了equals(),它通过对列表中的所有元素调用equals() 来实现。如果列表的元素都相等,则列表相等。而且,正如另一个答案所提到的,clone() 方法会创建一个新列表,其中包含与原始对象相同的对象(而非副本)。

【讨论】:

以上是关于Java clone() 和 equals() 检查的主要内容,如果未能解决你的问题,请参考以下文章

Java中Object类中的方法

理解Java中的hashCode和equals 方法

java面试题整理

如果Set包含具有某些字符串值的对象,如何检入java?

Effective Java 英文 第二版 读书笔记 Item 11:Override clone judiciously

Java基础—— 常用类