Oracle java泛型教程

时间:2015-10-12 20:41:36

标签: java generics

我正在通过Oracle java教程。我目前正在使用泛型,我在课程结束时对问题8感到困惑,下面提供了解决方法。 具体来说,我不理解T延长ObjectComparable<? super T>背后的理由。仅T只是扩展Comparable<? super T>还不够,还有T扩展Object的优势吗?

问题:

编写一个通用方法来查找列表[开头,结尾]范围内的最大元素。

答案:

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

1 个答案:

答案 0 :(得分:1)

我可以找到<T extends Object & Comparable<? super T>而不是T extends Comparable<? super T>的唯一原因是在生成方法时向后兼容。

根据Angelika Langer的Java Generics FAQ

  

有时候,必须注意一般化可能会改变字节代码中某些方法的签名这一事实。更改签名将破坏无法重新编译的现有代码,并依赖于旧版和新版.class文件的二进制兼容性。

在这种情况下,Java自己的Collections.max曾经在1.5之前返回Object,即泛型的到来。通用时,可以在没有extends Object的情况下声明此方法,并且它可以在单独的情况下正常工作。

public static <T extends Comparable<? super T>> T max(Collection <? extends T> coll)

但是,出于字节码的目的,此方法的擦除使此方法返回Comparable,而不是Object,这是向后不兼容的。

要解决此问题,extends Object作为第一个绑定被插入,因此此方法的返回类型的擦除将保持为Object

这解决了1.5中Java泛型的向后不兼容问题。

然而,教程中提出的问题是:

  

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

您正在编写自己的新方法,因此尚无向后兼容性。

>在本教程问题的答案中extends Object是不必要的。

另外

在字节码(javap -c Algorithm.class)中,所有类型都经历类型擦除,甚至是局部变量maxElem

  public static <T extends java.lang.Comparable<? super T>> T max(java.util.List<? extends T>, int, int);
Code:
   0: aload_0
   1: iload_1
   2: invokeinterface #2,  2            // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;

get方法已返回Object。那么它如何在compareTo中调用Comparable

   7: astore_3
   8: iinc          1, 1
  11: iload_1
  12: iload_2
  13: if_icmpge     49
  16: aload_3
  17: checkcast     #3                  // class java/lang/Comparable
  20: aload_0
  21: iload_1
  22: invokeinterface #2,  2            // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
  27: invokeinterface #4,  2            // InterfaceMethod java/lang/Comparable.compareTo:(Ljava/lang/Object;)I

编译器已向Comparable插入隐式强制转换,以便可以调用compareTo方法。它声称列表中的对象是Comparable,因为第二个上限是Comparable<? super T>

  32: ifge          43
  35: aload_0
  36: iload_1
  37: invokeinterface #2,  2            // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
  42: astore_3
  43: iinc          1, 1
  46: goto          11
  49: aload_3
  50: areturn
}