Ответ 1
Проблема связана с спецификацией JLS, которая предусматривает, что в противном случае неопределяемые аргументы типа должны быть определены как Object
, даже если они не удовлетворяют границам (и, следовательно, запускают ошибку компиляции).
Ниже приводится отрывок из отчета "ошибка" (который был дополнительно аннотирован для ясности):
"Bug" ID 6299211 - тип типа метода: логический вывод для null
Эта программа не компилируется:
public class Try { void m() { java.util.Collections.max(null); } }
Состояние: ЗАКРЫТО, НЕ ДЕФЕКТ.
Оценка: ЭТО НЕ БЫЛО. Алгоритм вывода не может собрать какую-либо информацию из аргумента (
null
), и метод не вызывается в месте, где ожидаются ожидаемые значения. В таких случаях компилятор должен вывестиjava.lang.Object
для переменной типа.JLS 15.12.2.8 Вывод аргументов неразрешенного типа
Любые оставшиеся переменные типа, которые еще не были выведены, затем выводятся с типом
Object
Однако
Object
не является подтипомComparable<? super Object>
и, следовательно, не входит в пределы переменной типа в объявленииCollections.max
:
<T extends
Object & Comparable<? super T>
> T max(Collection<? extends T>)
Дальнейшие исследования
Использование явных параметров типа "исправляет" проблему:
HowBizarre.<Number,Integer>doIt(null); // compiles fine in javac
Чтобы показать, что это имеет меньшее отношение к аргументу null
и больше относится к абсолютному отсутствию информации о типе inferrence, вы можете попробовать, например. либо из следующих объявлений:
<T,U extends Comparable<T>> void doIt()
<T extends Number,U extends T> void doIt()
В любом случае вызов doIt();
не компилируется в javac
, так как он должен вывести U
как Object
в соответствии с 15.12.2.8, даже если это приведет к ошибке компиляции.
Примечание по Eclipse
Хотя ни один из фрагментов выше не компилируется в какой-либо версии javac
, они все делают в некоторой версии Eclipse. Это может означать ошибку в части Eclipse. Было известно, что между различными компиляторами существуют разногласия.