【问题标题】:Searching the maximal element in an array with generics [duplicate]使用泛型搜索数组中的最大元素[重复]
【发布时间】:2014-03-15 10:30:50
【问题描述】:

任务:

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

【问题讨论】:

  • 我不明白您问题的“我可以使用哪些类型?”
  • 可以使用任何扩展Comparable接口的类型,否则不保证有compareTo函数。
  • @BoristheSpider 是的,只需阅读您提供的链接并删除我的评论...我每天都学到新东西
  • 为什么投反对票?这是一个很好的问题,即使是经验丰富的 Java 开发人员也会感到困惑。
  • @BoristheSpider:我认为这有可能成为一个好问题。但是,现在我认为它的表达不是特别好(“我可以使用哪些类型?”甚至是什么意思?)[顺便说一句,我没有投反对票。]

标签: java generics


【解决方案1】:

我假设这里有两个问题:

  • 为什么需要边界Object
  • 为什么要使用Comparable&lt;? super T&gt; 而不是Comparable&lt;T&gt;

对于第一个问题,实际上并不需要给出明确的Object 界限,但这可能取决于您希望擦除方法的样子。使用明确的Object 绑定,您的类型参数将被擦除为Object,否则,它将被擦除为Comparable。大多数情况下,您不会发现任何需要提供显式绑定,但这可能是 API 兼容性所必需的,如 this post 中所述。

至于第二个问题,使用Comparable&lt;? super T&gt; 通常是一个好主意,如果您想将列表传递给List&lt;T&gt;,其中T 是可比较的。为什么?假设你有一个类:

class Employee implements Comparable<Employee> { }

和一个子类:

class PartTimeEmployee extends Employee { }

并且您想将List&lt;PartTimeEmployee&gt; 传递给List&lt;T&gt;。在您意识到您的PartTimeEmployee 并没有真正实现Comparable&lt;PartTimeEmployee&gt; 而是Comparable&lt;Employee&gt; 之前,这似乎很简单,而且很容易。因此,您要做的是将T 的边界更改为:

T extends Comparable<? super T>

.. 然后你可以传递一个List&lt;PartTimeEmployee&gt;,因为它现在满足绑定。

您必须这样做的原因是,擦除(再次?)。是的。在第一次看到该错误时,您可能会从椅子上跳下来并通过执行以下操作快速使 PartTimeEmployee 也具有可比性:

class PartTimeEmployee extends Employee implements Comparable<PartTimeEmployee>

...但是,嘿,你做错了。 Java 泛型不允许您从相同泛型类型的两个不同参数化实例中实现或扩展。你是说,PartTimeEmployee 同时实现了Comparable&lt;Employee&gt;Comparable&lt;PartTimeEmployee&gt;。有了这个,您的PartTimeEmployee 中有两种方法:

compareTo(PartTimeEmployee)
compareTo(Employee)

擦除后,它们都会变成:

compareTo(Object)
compareTo(Object)

你现在有重复的方法。这就是为什么它是非法的。

但是在这种情况下,由于您有 List&lt;? extends T&gt; 作为参数类型,我认为您可能会使用 Comparable&lt;T&gt;,因为当您传递 List&lt;PartTimeEmployee&gt; 时,T 将被推断为 Employee ,因此将满足界限。

【讨论】:

    【解决方案2】:

    问题:public static &lt;T extends Object &amp; Comparable&lt;? super T&gt;&gt;public static &lt;T extends Comparable&lt;T&gt;&gt;的区别

    第一部分:为什么是extends Object

    正如this answer 中很好解释的那样,这是出于与 1.5 之前的 API 向后兼容的原因。所以,如果你没有这个问题,你可以删除它。

    第二部分:为什么是Comparable&lt;? super T&gt; 而不是Comparable&lt;T&gt;

    让我们采用两个类AB,其中B 继承A。你让两者都实现了Comparable,但自然排序的逻辑在AB 中是相同的。因此,您将编写类定义为:

    public class A implements Comparable<A> {}
    
    public class B extends A {}
    

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

    来自 JDK 的示例:java.util.Datejava.sql.Date。后者继承了前者。你会看到java.sql.Date实现了Comparable&lt;**java.util.Date**&gt;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-03-30
      • 1970-01-01
      • 2015-04-18
      • 2017-02-27
      • 2021-01-20
      • 2019-11-23
      • 1970-01-01
      相关资源
      最近更新 更多