为什么我不能在保留compareTo()契约的同时使用新的值组件扩展可实例化类?

问题描述 投票:0回答:2

Per Joshua Blotch 的《Effective Java》

无法用新值扩展可实例化类 组件,同时保留

compareTo()
合约,除非您是 愿意放弃面向对象抽象的好处

您能否通过示例和挑战来解释上述内容? 您还能解释一下 Joshua 所说的 “价值组件” 是什么意思以及还有哪些其他类型的组件可用?

这可以让你自由地实现你喜欢的任何

compareTo
方法 第二类,同时允许其客户端查看 需要时,第二类作为第一类的实例。

你能否解释一下约书亚所说的“第二类作为第一类的实例”

java class oop comparable
2个回答
10
投票

您能否通过示例和挑战来解释上述内容?

当然。考虑这样的两个类 - 我省略了所有的 getter、setter 等,但希望你能明白:

class NamedThing {
    String name;
}

class Person extends NamedThing {
    Date dateOfBirth;
}

忽略这是否是一个的继承示例——它是一个简单的示例。

对于

NamedThing
来说,根据名称(按字母顺序排列)进行比较是很自然的。

Person
实施比较也是很自然的,首先比较姓名(因此在这方面保持一致),然后检查一个出生日期是否早于另一个出生日期。

现在想象一下:

NamedThing person1 = new Person("Jon", date1);
NamedThing person2 = new Person("Jon", date2);
NamedThing thing = new NamedThing("Jon");

int comparison1 = person1.compareTo(thing);
int comparison2 = person2.compareTo(thing);
int comparison3 = person1.compareTo(person2);
int comparison4 = thing.compareTo(person1);

您希望所有这些结果是什么?如果

Person.compareTo
足够聪明,能够 only 将其日期处理应用于
Person
的实例,那么您可能会期望
comparison1
comparison2
为 0,但
comparison3
为非零。

大概

comparison4
have 为 0,因为它使用
NamedThing.compareTo

比较名称。

从根本上来说,尝试比较不同类型的实例存在一个问题。它最终会更清晰地定义比较的“外部”,它定义了它将使用什么比较。因此,您可以有一个仅接受 Comparator<Person>

 引用并使用名称和日期的 
Person
,以及仅按名称进行比较的 
Comparator<NamedThing>
。该行为将具有对称性和清晰度。

你能解释一下约书亚所说的第二类作为第一类的实例是什么意思吗?

你断章取义了。它是:“将第二类的实例视为第一类的实例” - 例如

// First class = Animal // Second class = Zebra Animal person = new Zebra();
    

0
投票
    这意味着对于每个子类,您必须重写
  1. compareTo
     方法。
  2. 转换到超类称为
  3. upcasting
© www.soinside.com 2019 - 2024. All rights reserved.