Проблема связана со спецификацией JLS, которая предписывает, что в противном случае неопределяемые аргументы типа должны выводиться как Object
, даже если он не удовлетворяет границам (и, следовательно, вызывает ошибку компиляции).
Ниже приведен отрывок из отчета об ошибке (который был дополнительно аннотирован для ясности):
Эта программа не компилируется:
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
, сколько с абсолютным отсутствием информации для определения типа, вы можете попробовать, например, одно из следующих объявлений:
<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. Известно, что между разными компиляторами существуют разногласия.
Похожие вопросы