【问题标题】:Oracle java generics tutorial [duplicate]Oracle java泛型教程[重复]
【发布时间】:2015-10-12 20:41:36
【问题描述】:

我正在学习 Oracle java 教程。我目前正在学习泛型,我对课程结束时的问题 8 感到困惑,下面提供了解决方案。 具体来说,我不明白让T 扩展ObjectComparable<? super T> 背后的基本原理。 T 简单地扩展Comparable<? super T> 还不够,还有T 扩展Object 有什么好处?

问题:

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

答案:

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

【问题讨论】:

  • 这篇文章被标记为重复的问题肯定是相关的,但它并不完全是重复的。另一个问题是为什么Collections.maxextends Object,但是在这个问题的链接教程问题/答案中,答案(向后兼容性)不适用。
  • @rgettman 同意。我最初链接到这个问题现在是 andstackoverflow.com/questions/18411527/… 的“重复”,但正是出于这个原因删除了第一个链接:向后兼容性不适用于此处。另一个问题的答案很好地解释了类型擦除,因此关闭可能仍然是合理的。

标签: java generics


【解决方案1】:

我能找到 &lt;T extends Object &amp; Comparable&lt;? super T&gt; 的唯一原因,而不是 T extends Comparable&lt;? super T&gt;,是为了在生成方法时向后兼容。

根据 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。那么它是如何调用Comparable中的compareTo呢?

   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&lt;? super T&gt;,它断言列表中的对象是Comparable

  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
}

【讨论】:

  • 好的,这是有道理的。只是为了澄清一下,我认为 T 正在为方法的返回类型擦除到 Object 但在方法的主体中是 Comparable 的想法是否正确?
  • 我问是因为方法体内的变量 maxElem(类型为 T)被用作 Comparable。
  • 我已经更新了我的答案;类型擦除适用,但在需要调用 compareTo 时插入强制转换。
  • 非常感谢,谢谢。
猜你喜欢
  • 2010-09-26
  • 2014-01-12
  • 2018-04-27
  • 2015-10-08
  • 2012-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-24
相关资源
最近更新 更多