2015-10-12 2 views
2

Я работаю над учебниками Oracle java. В настоящее время я использую дженерики, и я смущен вопросом 8 в конце урока, решение которого приводится ниже. В частности, я не понимаю причины, по которым T распространяют как Object, так и Comparable<? super T>. Разве это недостаточно для T, чтобы просто расширить Comparable<? super T>, в чем преимущество T продлить Object?Oracle java generics tutorial

Вопрос:

Написать шаблонный метод, чтобы найти максимальный элемент в диапазоне [начало, конец) списка.

Ответ:

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

Вопрос о том, что этот пост отмечен как дубликат, определенно связан, но это не совсем дубликат. Другой вопрос заключается в том, почему 'Collections.max' имеет' extends Object', но в связанном учебном вопросе/ответе от этого вопроса ответ (обратная совместимость) не применяется. – rgettman

+0

@ rgettman Согласен. Первоначально я был связан с вопросом, что этот теперь является «дублированным» ** и ** на http://stackoverflow.com/questions/18411527/how-to-write-a-generic-method-to-find- метод-maximal-element-and-invoke-that-method, но по этой причине удалили первую ссылку: обратная совместимость здесь не применима. Ответ на другой вопрос объясняет вещь стирания типа довольно хорошо, поэтому закрытие все еще может быть оправдано. – Marco13

ответ

1

Единственная причина, которую я могу найти, чтобы иметь <T extends Object & Comparable<? super T>, в отличии от T extends Comparable<? super T>, для обеспечения обратной совместимости при родовой методе.

Согласно Ангелика Лангера Java Generics FAQ:

Иногда, нужно обратить внимание на то, что родовыми может изменить подпись некоторых методов в байт-код. Изменение подписи приведет к поломке существующего кода, который нельзя перекомпилировать, и полагается на двоичную совместимость старой и новой версии файла .class.

В этом случае Java Collections.max используется для возврата Object до 1,5, прихода дженериков. При генерации этот метод может быть объявлен без extends Object, и он будет работать корректно изолированно.

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

Однако стирание этого метода, для целей байт-кода, этот метод имеет возвращающегося Comparable вместо Object, который представляет собой обратную несовместимость.

Для решения этой проблемы в качестве первой границы было вставлено extends Object, так что стирание возвращаемого типа этого метода оставалось бы Object.

Это разрешило проблему несовместимости в обратном направлении для генериков Java в 1.5.

Однако вопрос в учебнике говорится:

Написать шаблонный метод, чтобы найти максимальный элемент в диапазоне [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 
} 
+0

Хорошо, это имеет смысл. Как раз пояснить, правильно ли я полагаю, что T стирает Object для возвращаемого типа метода, но сравнивается внутри тела метода? – Duncan3142

+0

Я прошу, потому что переменная maxElem (которая имеет тип T) внутри тела метода используется как Comparable. – Duncan3142

+1

Я обновил свой ответ; тип стирания применяется, но при необходимости добавляется бросок для вызова 'compareTo'. – rgettman