任务:
编写一个通用方法来查找列表[begin,end]范围内的最大元素。
答案:
public final class Algorithm {
public static <T extends Object & Comparable<? super T>>
T max(List<? extends T> list, int begin, int end) {
T maxElem = list.get(begin);
for (++begin; begin < end; ++begin)
if (maxElem.compareTo(list.get(begin)) < 0)
maxElem = list.get(begin);
return maxElem;
}
}
请解释一下如何使用这种方法?与以下签名有什么不同:
public static <T extends Comparable<T>>
T max(List<? extends T> ar, int begin, int end) { ... }
答案 0 :(得分:1)
问题:public static <T extends Object & Comparable<? super T>>
和public static <T extends Comparable<T>>
第一部分:为什么extends Object
?
正如this answer中详细解释的那样,这用于1.5之前API的向后兼容性原因。因此,如果您没有遇到此问题,可以将其删除。
第二部分:为什么Comparable<? super T>
而不是Comparable<T>
?
让我们选择两个课程A
和B
,B
继承A
。您可以同时使用Comparable
,但自然排序的逻辑在A
和B
中是相同的。因此,您将编写类定义:
public class A implements Comparable<A> {}
public class B extends A {}
因此,B
实现了Comparable<A>
,而不是Comparable<B>
。如果它执行后者,您将无法对List<A>
进行排序,其中列表的元素都是B
和A
类型。因此super
。
JDK的一个例子:java.util.Date
和java.sql.Date
。后者继承了前者。您会看到java.sql.Date
实施Comparable<**java.util.Date**>
答案 1 :(得分:1)
我假设这里有两个问题:
Object
Comparable<? super T>
代替Comparable<T>
。对于第一个问题,实际上并不需要提供明确的Object
界限,但这可能取决于您希望删除方法的方式。如果明确Object
绑定,您的类型参数将被删除为Object
,如果没有,则会将其删除为Comparable
。大多数情况下,您不会发现需要提供明确的绑定,但这可能是API兼容性所必需的,如this post中所述。
关于第二个问题,如果您想将列表传递给Comparable<? super T>
,List<T>
可以比较,那么使用T
通常是个好主意。为什么?假设你有一个班级:
class Employee implements Comparable<Employee> { }
和一个子类:
class PartTimeEmployee extends Employee { }
并且您希望将List<PartTimeEmployee>
传递给List<T>
。这可能看起来很简单,而且在你意识到PartTimeEmployee
并没有真正实现Comparable<PartTimeEmployee>
而是实现Comparable<Employee>
之前不容易。所以,你要做的是,将T
的界限改为:
T extends Comparable<? super T>
..然后你可以传递一个List<PartTimeEmployee>
,因为它现在满足了界限。
您执行此操作的原因与 erasure (再次?)有关。是。在第一次看到这个错误时,您可以跳下椅子并快速通过这样做来PartTimeEmployee
进行比较:
class PartTimeEmployee extends Employee implements Comparable<PartTimeEmployee>
......但是,嘿,你在那里做错了。 Java泛型不允许您从相同泛型类型的两个不同参数化实例化实现或扩展。您这样说,PartTimeEmployee
同时实施Comparable<Employee>
和Comparable<PartTimeEmployee>
。有了这个,您可以在PartTimeEmployee
中使用两种方法:
compareTo(PartTimeEmployee)
compareTo(Employee)
擦除后,它们都会变成:
compareTo(Object)
compareTo(Object)
现在你已经重复了一些方法。这就是为什么它是非法的。
但是在这种情况下,由于您有List<? extends T>
作为参数类型,我认为您可能会使用Comparable<T>
,因为当您传递List<PartTimeEmployee>
时,{{1}将被推断为T
,因此将满足界限。