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