使用泛型搜索数组中的最大元素

时间:2014-03-15 10:30:50

标签: java generics

任务:

  

编写一个通用方法来查找列表[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) { ... }

2 个答案:

答案 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>

让我们选择两个课程ABB继承A。您可以同时使用Comparable,但自然排序的逻辑在AB中是相同的。因此,您将编写类定义:

public class A implements Comparable<A> {}

public class B extends A {}

因此,B实现了Comparable<A>,而不是Comparable<B>。如果它执行后者,您将无法对List<A>进行排序,其中列表的元素都是BA类型。因此super

JDK的一个例子:java.util.Datejava.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,因此将满足界限。