【问题标题】:How to Write a generic method to find the maximal element and invoke that method?如何编写通用方法来查找最大元素并调用该方法?
【发布时间】:2013-08-23 20:43:39
【问题描述】:

当我尝试解决练习时from generics tutorial Q&A我的答案略有不同

我的答案

public static <T extends Comparable<? super T>>
    T max(List<? extends T> list, int begin, int end) //Option1

public static <T extends Comparable<T>>
    T max(List<? extends T> list, int begin, int end) //Option2

来自下面引用的答案

所以我的问题是

  • 选项1:如果T extends Object &amp; Comparable&lt;? super T&gt; 被替换为T extends Comparable&lt;? super T&gt; 会有什么不同。 extends Object 不是隐含的吗?

  • Option2 : 如果 Comparable&lt;? super T&gt; 被替换为 Comparable&lt;T&gt; 会有什么不同吗?如果是怎么办?

  • Eclipse 代码完成在 Ctrl+1 max(list, 1, 10); 上创建局部变量 List&lt;? extends Comparable&lt;? super Comparable&lt;? super T&gt;&gt;&gt; list;,这有点长。如何定义扩展 Comparable&lt;? super T&gt; 的类(层次结构),创建列表并将实例添加到列表并调用以下方法?基本上我想知道在将类实例A or B 添加到class B extends A 的列表中之后如何调用max()


编写一个泛型方法来查找范围内的最大元素 [开始,结束)列表。

答案:

import java.util.*;

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;
    }
}

【问题讨论】:

  • 我不太明白你的第三个问题。你能详细说明一下吗?
  • eclipse 为哪个方法调用创建了该局部变量?我不明白它为什么会这样做。至少嵌套的 Comparable 泛型类型在这里确实不合理。
  • 我想我已经为你的第三个问题添加了答案。您可以在那里查看ParentChild 代码。我想这就是你想要的。
  • @RohitJain 当您输入 max(list, 1, 10); 并执行 ctrl1 并选择 'create local variable list' 时,它将被 eclipse 插入。是的,你已经回答了第三次谢谢:)。当 eclipse 创建那个冗长的声明时,我有点困惑

标签: java list generics


【解决方案1】:

如果 Comparable&lt;? super T&gt; 被替换为 Comparable&lt;T&gt; 会有什么不同吗?如果有怎么办?

请记住,Comparables 始终是消费者,即 Comparable&lt;T&gt; 消耗 T 实例,因此应该始终使用 Comparable&lt;? super T&gt; 而不是 Comparable&lt;T&gt;(引用 - PECS)。如果您正在比较其超类实现Comparable&lt;SuperType&gt; 的类型,这将有所不同。考虑以下代码:

class Parent implements Comparable<Parent> {
    protected String name;

    @Override
    public int compareTo(Parent o) {
        return this.name.compareTo(o.name);
    }
}

class Child extends Parent {
    public Child(String name) {
        this.name = name;
    }
}

现在,如果您将类型参数指定为 T extends Comparable&lt;T&gt;,您将无法为 List&lt;Child&gt; 调用该方法,因为 Child 没有实现 Comparable&lt;Child&gt;Comparable&lt;Parent&gt;

public static <T extends Comparable<T>> T max(List<? extends T> list, int begin, int end) {
    ...
}

public static void main(String[] args) {
    List<Child> list = new ArrayList<Child>();
    max(list, 0, 2);  // Error with current method. Child does not implement Comparable<Child>
}

因此类型参数边界应该是T extends Comparable&lt;? super T&gt;

请注意,您不能将您的 Child 类更改为:

class Child extends Parent implements Comparable<Child>

因为在这种情况下,Child 类会从相同泛型类型的不同实例扩展而来,这是不允许的。


如果将T extends Object &amp; Comparable&lt;? super T&gt; 替换为T extends Comparable&lt;? super T&gt;,会有什么不同吗? extends Object 不是隐含的吗?

嗯,这两个界限是有区别的。在第 1st 界限中,类型参数的擦除为 Object,而在第 2nd 界限中,擦除为 Comparable

因此,如果没有Object 绑定,您的代码将编译为:

public static Comparable max(List list, int begin, int end)

当您生成旧版非通用代码时,可能会出现此问题。有必要将Object 也作为上限,以避免破坏字节码的兼容性。您可以在此链接上阅读更多信息:Angelika Langer - Programming Idioms

【讨论】:

  • 方法的擦除只对输入参数类型产生影响,而不是返回类型,Object 绑定在那里没有影响:它仍然是max(List, int, int)Object 在这里真的没必要。
  • @LouisWasserman。好吧,乍一看我也有同样的想法,然后我阅读了最后添加的链接。据说是为了保持字节码的兼容性。
  • @RohitJain 事实上max(list, 0, 2); 可以正常编译。但Child child = max(list, 0, 2); 不会编译。
【解决方案2】:

通配符似乎比必要的多。我可能会去

public static <T extends Comparable<? super T>>
    T max(List<T> list, int begin, int end)

一个更受限制的版本:

public static <T extends C, C extends Comparable<C>>
    T max(List<T> list, int begin, int end)

T 必须有一个与自身相当的超类型。例如T 不能是Foo

    class Foo implements Comparable<Object>

Foo 无论如何都没有意义; Comparable 只能与它自己的同类进行有意义的比较。子句C extends Comparable&lt;C&gt; 承认这一事实。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-17
    相关资源
    最近更新 更多