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() 检查的主要内容,如果未能解决你的问题,请参考以下文章
Effective Java 英文 第二版 读书笔记 Item 11:Override clone judiciously