Почему этот код терпит неудачу с 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());