可比接口声明

时间:2017-10-22 19:33:17

标签: java generics

Comparable接口变为通用时,声明变为

interface Comparable<T>

真的应该是

interface Comparable<T extends Comparable<T>>

T没有延伸Comparable是没有意义的,因为实现者必须确保

a.compareTo(b)

b.compareTo(a)

总是有相反的信号。

我一直认为获得声明“错误”的原因与生成现有界面的问题有关,但我无法解释它。

有没有人有任何见解?

1 个答案:

答案 0 :(得分:3)

  

真的应该是

     

interface Comparable<T extends Comparable<T>>

但是,这并没有真正为您提供interface Comparable<T>未获得的任何内容。

您提及a.compareTo(b)b.compareTo(a)的内容,但请注意,您的声明(interface Comparable<T extends Comparable<T>>)实际上并不能确保a.compareTo(b)有效,b.compareTo(a) 1}}编译。如果aComparable<T>,则a.compareTo(b)要求bTComparable<T>也是b.compareTo(),因此T需要b.compareTo(a) {1}}。这并不能证明a有效,因为Comparable<T>class Foo implements Comparable<Foo>。作为一个例子,请考虑class Bar implements Comparable<Foo>a。如果Bar类型为bFoo类型为Comparable,那么您的a.compareTo(b)声明,b.compareTo(a)会编译但{{1}不编译(这与Comparable的原始声明发生的情况也是一样的)。要有一个绑定可以保证当a.compareTo(b)工作时,b.compareTo(a)也可以工作,你需要有类似interface Comparable<T extends Comparable<Comparable<T>>>的东西,但那将是一个无用的接口,因为没有人T 1}}与Comparable<T>相当。

更基本的是,在泛型中添加绑定的目的是允许您编译一些无法编译的东西,或者需要一个没有绑定的强制转换。请记住,Java会在编译时检查代码是否类型安全 - 它只允许您使用在编译时声明的类型编译它知道的内容(除非您添加显式强制转换,在这种情况下,您负责转换的正确性)。因此,添加绑定不会增加类型安全性 - 无论有没有绑定,Java编译器只会编译可证明类型安全的代码(显式强制转换或原始类型转换除外)。绑定的不同之处在于,通过添加约束,它允许Java接受 more 代码作为类型安全,因为约束允许Java推断出以前无法实现的正确性。所以只有在允许你编译你不能没有绑定的东西时才能添加一个绑定,或者需要在没有绑定的情况下添加显式的强制转换。否则,增加复杂性没有任何好处的重点是什么?

在这里,您不会找到任何可以使用您的Comparable声明编译但不会使用原始声明进行编译的代码的实际用例。我见过的唯一现实用例,其中声明interface Foo<T extends Foo<T>>允许编译的内容不能与interface Foo<T>进行编译,这类似于Builder模式,其中Foo<T>有一个方法,返回T,由于我们知道TFoo<T>的子类型,我们可以从Foo<T>转到Foo<T>并链接这些操作,不知道T的具体类型。但Comparable并非如此 - Comparable没有返回T的方法。

如果您的类或方法具有需要排序或排序的类似类型,则它必须是一个通用方法或类,要求该类型与其自身相当(例如{{1} }或class SortedList<T extends Comparable<? super T>>)。 <T extends Comparable<? super T>> void sort(List<T>)声明中的任何约束都不能确保该类型与其自身相当。

如果有人决定写一个类型与完全不相关的类型(甚至不是Comparable的东西)的类,那么从类型安全的角度来看这很好。是的,您指出它可能违反了Comparable的文档,但这是代码行为问题,而不是类型安全问题。他们的类可能不会非常有用,因为它不会满足大多数使用.compareTo()的地方的界限,这些界限可能会要求该类型与其自身相当。如果有一个地方需要Comparable没有绑定要求类型与自己相比,那么他们可以在那里使用他们的类,但这仍然是类型安全的,因为这个地方的事实不要求类型与自身相比意味着它自己的代码不依赖于这个事实来安全地编译(或者他们使用显式强制转换,在这种情况下它们负责正确性)。在任何情况下,有人可能会编写一个(大多数是无用的,可能违反文档)类,这个类与不具有可比性的东西相比,不会影响你编写自己的类的能力,而这个类与自身相当,而且没有类型安全添加任何边界的原因。