最大元素 - 孙的答案VS我的

  发布于 2023-02-13 20:53

在阅读了Sun关于泛型的文档之后,我转到了http://docs.oracle.com/javase/tutorial/java/generics/QandE/generics-questions.html上的Q和E部分.

对于Q8 -

编写一个通用方法来查找列表[begin,end]范围内的最大元素.

我写的代码是:

private static > T max(List l, int i, int j) {
    List sublist = l.subList(i, j);
    System.out.println("Sublist "+sublist);
    int c = 0;T max = null;
    for(T elem: sublist) {
        if(c == 0 || max.compareTo(elem) < 0) {
            max = elem;
        } ++c;
    }
    return max;
}

而Sun的回答是:

public static >

    T max(List 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;
}

有人可以告诉我一个例子,Sun的版本比我的更好吗?

编辑:我想比较2个解决方案的效率主要是基于方法声明中使用的类型参数/边界而不是逻辑,例如在什么情况下Sun的版本对于函数的调用者更好?基本上我不明白为什么你需要List太阳使用的,而不是我用过的东西.

一个例子非常受欢迎,因为我已经被理论所压倒.(对不起,如果听起来很粗鲁,但我不是故意的).

提前谢谢,穆斯塔法

1 个回答
  • 这里有两个单独的泛型问题.

    为什么要使用交叉类型?

    也就是说,为什么解决方案使用T extends Object & Comparable<T>而不是更简单T extends Comparable<T>?(我在本节中省略了通配符;我将在下面覆盖它们.)

    我不认为这与类型系统Object & Comparable<T>有任何不同Comparable<T>,因为每个对象都会延伸Object.也就是说,没有T延伸的类型Comparable<T>也不会扩展Object & Comparable<T>.

    但是有一点不同.的交叉型擦除到交点的第一分量,所以T extends Object & Comparable<T>擦除到ObjectT extends Comparable<T>擦除到Comparable.考虑该max方法的两个替代声明:

    <T extends Comparable<T>> T max1(List<T> list) { ... }
    
    <T extends Object & Comparable<T>> T max2(List<T> list) { ... }
    

    如果使用转储这些方法的签名,则javap -s可以看到显示已擦除类型的内部签名:

    <T extends java/lang/Comparable<T>> T max1(java.util.List<T>);
      Signature: (Ljava/util/List;)Ljava/lang/Comparable;
    
    <T extends java/lang/Object & java/lang/Comparable<T>> T max2(java.util.List<T>);
      Signature: (Ljava/util/List;)Ljava/lang/Object;
    

    谁在乎擦除类型?JVM呢.JVM基于匹配参数类型和返回类型来查找方法.因此,擦除的返回类型可能很重要.

    事实上,从二进制兼容性的角度来看,它具有重要意义.在Java SE 5之前,当引入泛型时,Collections.max声明了该方法并具有如下的擦除签名:

    public static Object max(Collection coll)
      Signature: (Ljava/util/Collection;)Ljava/lang/Object;
    

    在Java SE 5及更高版本中,声明和擦除签名是:

    public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
      Signature: (Ljava/util/Collection;)Ljava/lang/Object;
    

    至关重要的是,擦除的签名是相同的.

    相反,如果没有使用交集类型声明Java SE 5声明,它将如下所示:

    public static <T extends Comparable<? super T>> T max(Collection<? extends T> coll)
      Signature: (Ljava/util/Collection;)Ljava/lang/Comparable;
    

    这将是二进制不兼容.针对旧版本JDK编译的二进制文件将引用max该返回的版本Object.如果使用此备用,不兼容的声明对JDK运行,max则会返回唯一的版本Comparable,导致在NoSuchMethodError链接时抛出.

    因此,使用<T extends Object & Comparable<T>>它实际上是为了控制此声明的擦除,这是由二进制兼容性考虑因素驱动的.在这一点上,该教程似乎有些误导.Collections.maxJava SE中的实际声明是这种二进制兼容性的方式.但是如果你是第一次宣布这种方法,我不认为以这种方式使用交集类型是有用的.

    为什么声明中使用了通配符?

    也就是说,而不是:

    static <T extends Comparable<T>> T max(List<T> list)
    

    为什么使用通配符:

    static <T extends Comparable<? super T>> T max(List<? extends T> list)
    

    这里,通配符对于在存在子类型时更灵活地使用该方法是必要的.考虑以下:

    class A implements Comparable<A> { ... }
    
    class B extends A { }
    
    List<B> bList = ...;
    B bMax = max(bList);
    

    如果使用了非通配符声明,则不会T匹配.为了使这项工作,Comparable<? super T>是必要的.这允许T推断为B一切正常.

    我必须承认,我无法找到一个示例,说明List<? extends T>在这种情况下需要的原因.如果简单地声明参数,此示例工作正常List<T>.它可能List<? extends T>用于文档目的,以指示仅从列表中检索元素,并且不修改列表.(有关这方面的更多信息,请参阅泛型章节中的Bloch的Effective Java,他讨论了PECS - "Producer Extends,Consumer Super";或Naftalin和Wadler的Java Generics and Collections,他们讨论了"Put and Get Principle".)


    链接:

    为什么T在Collections.max()签名中被Object绑定?

    Angelika Langer的FAQ条目

    Java Generics:什么是PECS?

    为什么我们需要在Collections.max()方法中使用有界wilcard

    2023-02-13 20:59 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有