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