Почему этот код терпит неудачу с sourceCompatibility = 1,8
Следующий код работает при компиляции с исходной совместимостью = 1.7 или 1.6, но после переключения на 1.8:
public class Java8Wat {
interface Parcelable {
}
static class Bundle implements Parcelable {
public void put(Parcelable parcelable) {
}
public void put(Serializable serializable) {
}
public <T extends Parcelable> T getParcelable() {
return null;
}
}
static {
Bundle inBundle = new Bundle();
Bundle outBundle = new Bundle();
outBundle.put(inBundle.getParcelable());
}
}
Вывод компиляции:
Java8Wat.java:23: error: reference to put is ambiguous
outBundle.put(inBundle.getParcelable());
^
both method put(Parcelable) in Bundle and method put(Serializable) in Bundle match
Здесь репо с кодом ошибки: https://github.com/chalup/java8-wat. Просто запустите ./gradlew clean build
из каталога проекта.
Я просматривал JLS для Java 8, но я не нашел ничего подходящего.
Дополнительное наблюдение: код компилируется, если я изменяю подпись getParcelable()
на:
public Parcelable getParcelable()
Почему компилятор java считает put(Serializable)
потенциально применимым методом для вызова outBundle.put(inBundle.getParcelable())
и какие изменения следует внести в класс Parcelable/Bundle? Бонусный вопрос: почему эта ошибка возникает только на Java 8, а не на Java 7?
Ответы
Ответ 1
Я бы предположил, что это связано с изменениями в том, как делается вывод в java 8. И к тому, что Parcelable
является интерфейсом.
Из-за этого выведенный тип возвращаемого значения getParcelable
приводит к двусмысленному вызову, так как тип возвращаемого возврата может применяться к обоим методам.
В основном я хотел бы обратиться к этому другому вопросу для более ясного объяснения: Почему этот общий метод с привязкой возвращает какой-либо тип?
Что касается реального понимания того, как вывод работает в этом конкретном случае и почему он отличается от java 7 и 8, для этого потребуется более глубокое изучение часть JLS.
Ответ 2
Как говорится в сообщении reference to put is ambiguous
.
Вы должны раскрывать значение, чтобы компилятор знал, какой метод вы хотите использовать:
outBundle.put((Parcelable)Bundle.getParcelable());
или
outBundle.put((Serializable)Bundle.getParcelable());