我是Java编程的导师。我的学生目前被迫(不是我,而是一个不清楚的任务)为一个抽象类实现clone()、equals()和hashCode() 。
为抽象类实现 clone()、equals() 或 hashCode() 有意义吗?你能举一个有意义的例子吗?
我可以想象,当您有抽象类 a 的一些子类 x、y、z 时,这是有道理的。这些子类可能仅在方法的实现上有所不同,因此您不需要将这三个方法实现三次。但我无法想象会出现这种情况的任何情况。
我是Java编程的导师。我的学生目前被迫(不是我,而是一个不清楚的任务)为一个抽象类实现clone()、equals()和hashCode() 。
为抽象类实现 clone()、equals() 或 hashCode() 有意义吗?你能举一个有意义的例子吗?
我可以想象,当您有抽象类 a 的一些子类 x、y、z 时,这是有道理的。这些子类可能仅在方法的实现上有所不同,因此您不需要将这三个方法实现三次。但我无法想象会出现这种情况的任何情况。
我不会实施clone()
.
equals()
但是实现,hashCode()
并toString()
为所有子类提供默认行为是有意义的。如果孩子没有添加新的班级成员或根据需要补充,他们可以选择使用它。
误读了你的问题,并认为你也问过toString
- 同样的推理仍然适用
例如,基本上迭代集合并以用户友好的方式打印它的实现AbstractCollection
。toString()
直接子类:
AbstractList, AbstractQueue, AbstractSet, ArrayDeque, ConcurrentLinkedDeque
所以所有集合、列表和队列都共享该toString
方法。如果需要,每个子类都可以自由地重新实现它。
作为另一个示例,equals
实现低一级(在 AbstracList/Set 等中)。
另一方面,clone
是在最终实现中实现(例如 ArrayList),而不是在抽象类中。
底线:有时它是有意义的,但有时它没有,它可能不应该是适用于所有情况的义务。
1)clone()
方法非常有用,当你需要实现某种对象的深度复制,同时你不能只使用对这个对象的引用,而是需要它们的新实例。所以,重写这个方法是有意义的。
2)equals()
并且hashCode
是两个重要的方法,当您需要特殊行为时必须重写HashSet/HashMap
它们,其功能取决于这些方法的实现。因此,覆盖它们也是有道理的。
一个主要问题clone()
是有两种实现方式,派生类中的正确实现取决于其父类的功能。
如果父类及其所有祖先调用super.clone()
直到调用到达object.clone()
,那么派生类要做的正确的事情是调用super.clone
然后替换任何封装目标对象的可变状态而不是它们的身份的“添加”成员,用封装相同状态的新对象。如果派生类不包含任何封装可变对象状态的附加成员,则派生类不需要做任何事情,clone
而可以简单地使用父类的实现。
实现类的另一种方法clone()
是让它包含一个构造函数,该构造函数接受其自己类型的参数,并链接到父构造函数,该构造函数同样执行此操作,然后将所有适当的属性“新”复制到类型中传入实例到新实例。这种方法的一个优点是即使基类以clone
这种方式实现它也可以工作。然而,这种方法有两个缺点:
clone()
通过调用来实现,super.clone()
但有一个祖先没有,那么生成的对象最终将是父类型而不是派生类型——不是clone()
应该采取的方式。
方法 clone()、equals() 和 hasCode() 通常必须在实现该抽象类的类中实现,因为它们需要抽象类中不存在的字段。
然而,在某些情况下,equals()、hascode() 和可能的 clone() 在抽象类中实现是有意义的。(例如,equals() 在抽象容器类中有意义,例如 Collections 等)
对于 hashCode() 和 clone() 我更怀疑这是否有意义。
能说得通吗?
clone()
是有意义的。clone()
equals()
并hashCode()
有意义。该契约可以由它自己指定,也可以由它实现的超类或接口指定。它是否合适,即我们是否想要设计一个抽象超类来覆盖这些?
clone()
机制本身很少适用。一种适当的实现可能是显式地抛出 aCloneNotSupportedException
并生成它final
,并以这种方式防止子类实现Cloneable
。equals()
和hashCode()
明智的情况也是适当的情况。如果一个抽象超类本身可以满足平等契约规范,它应该这样做。并且它应该制定equals()
和hashCode()
方法final
,以防止LSP违规。我会引用 Josh Bloch 的话:没有办法在保留 equals 契约的同时扩展一个可实例化的类并添加一个值组件——Effective Java 2nd ed。