Java 8 autoboxing + generics: различное поведение в зависимости от метода
Я нашел кусок кода, который после переключения с Java 7 на Java 8 перестал компилироваться. Он не поддерживает ни одного нового Java 8, такого как лямбда или потоки.
Я сузил проблемный код до следующей ситуации:
GenericData<Double> g = new GenericData<>(1d);
Double d = g == null ? 0 : g.getData(); // type error!!!
Вы можете догадаться, чтоGenericData
конструктор имеет один параметр этого универсального типа иgetData()
Метод возвращает только этот общий тип. (Полный исходный код см. Ниже.)
Теперь меня беспокоит то, что в Java 7 этот код компилируется просто отлично, тогда как в Java 8 я получаю следующую ошибку:
CompileMe.java:20: error: incompatible types: bad type in conditional expression
Double d = g == null ? 0 : g.getData();
^
int cannot be converted to Double
Похоже, что Java 7 смогла сделать переход из int -> double -> Double, но Java 8 не может сразу перейти из int -> Double.
В частности, я нахожу забавным то, что Java 8делает принять код при измененииgetData()
вdata
то есть получить доступ кGenericData
значение через саму переменную вместо метода-получателя:
Double d2 = g == null ? 0 : g.data; // now why does this work...
Итак, у меня есть два вопроса:
Почему Java 8 не выводит типы, такие как Java 7, и не переводит мое int в double, а затем в autoboxing double в Double?Почему эта проблема возникает только с универсальным методом, но не с универсальной переменной?Полный исходный код:
public class CompileMe {
public void foo() {
GenericData<Double> g = new GenericData(1d);
Double d = g == null ? 0 : g.getData(); // type error!!!
Double d2 = g == null ? 0 : g.data; // now why does this work...
}
}
class GenericData<T> {
public T data;
public GenericData(T data) {
this.data = data;
}
public T getData() {
return data;
}
}
Чтобы проверить это, запустите компилятор следующим образом:
javac -source 1.7 -target 1.7 CompileMe.java # ok (just warnings)
javac -source 1.8 -target 1.8 CompileMe.java # error (as described above)
Наконец, в случае, если это имеет значение: я запускаю Windows 8 и Java 1.8.0_112 (64-разрядная версия).