Ответ 1
Этот ответ основан на этой статье Брайана Гетца от декабря 2014 года. Это последнее, что я мог найти по этому вопросу; обратите внимание, однако, что этот документ является "неофициальным эскизом", так что пока ничего не найдено относительно вашего вопроса.
Во-первых, List<int>
не будет подтипом List<Integer>
(Subtyping):
Изначально также может показаться разумным, что
Box<int>
может быть подтипом rawBox
. Но, учитывая нашу стратегию перевода, классBox
не может быть суперклассом любого класса, представляющегоBox<int>
, так как тогдаBox<int>
будет иметь полеt
типаObject
, тогда какt
должно быть типаint
. Таким образом,Box<int>
не может быть подтипом rawBox
. (И по той же причинеBox<int>
не может быть подтипомBox<Integer>
.)...
Так как generics инвариантны, неудивительно, что
List<int>
не является подтипомList<Integer>
. Немного удивительно, что специализированный тип не может взаимодействовать с его сырой копией. Однако это не является необоснованным ограничением; не только сырые типы не поощряются (были введены исключительно для поддержки постепенной миграции из не общего кода в общий код), но все же можно писать полностью общий код с использованием общих методов - см. "Общие методы".
В этом документе также перечислены "Проблемы с миграцией" и ссылки-примитивные перегрузки (проблема заключается в вашем вопросе) - один из них:
Некоторые перегрузки, которые действительны сегодня, станут проблематичными по специализации. Например, эти методы будут иметь проблему, если они специализированы с помощью
T=int
:public void remove(int position); public void remove(T element);
Такие перегрузки были бы проблематичными как со стороны специализации (какие методы для генерации), так и на стороне выбора перегрузки (какой метод вызывать.)
Предлагаемое решение называется методом "пилинга" :
Рассмотрим пару перегрузок в классе List-like:
interface ListLike<T> { public void remove(int position); public void remove(T element); }
Существующие использования
ListLike
будут связаны с эталонными экземплярами, поскольку это единственные экземпляры, которые в настоящее время разрешены в мире предварительной специализации. Обратите внимание, что в то время как совместимость требует, чтобы эталонные экземпляры имели оба этих метода, он не требует ничего от ссылок без ссылок (поскольку ни один из них не существует).Интуиция за пилингом заключается в том, чтобы заметить, что, хотя мы привыкли думать о существующем
ListLike
как об общем типе, это действительно может быть объединение типа, который является общим для всех экземпляров, и типа который является общим для всех ссылочных этапов.Если бы мы писали этот класс с нуля в мире после специализации, мы могли бы написать его как:
interface ListLike<any T> { void removeByIndex(int position); void removeByValue(T element); }
Но такое изменение теперь не будет либо совместимым с исходным кодом, либо совместимым с двоичным кодом. Однако пилинг позволяет нам добавлять эти методы к общему слою и реализовывать их в ссылочном слое, не требуя их в специализациях, восстанавливая совместимость:
interface ListLike<any T> { // New methods added to the generic layer void removeByValue(T element); void removeByIndex(int pos); layer<ref T> { // Abstract methods that exist only in the ref layer void remove(int pos); void remove(T element); // Default implementations of the new generic methods default void removeByIndex(int pos) { remove(pos); } default void removeByValue(T t) { remove(t); } } }
Теперь эталонные экземпляры имеют
remove(T)
иremove(int)
(а также новые методыremoveByIndex
иremoveByValue
), обеспечивающие совместимость, а специализации имеют непроблемные перегрузкиremoveByValue(T)
иremoveByIndex(int)
. Существующие реализацииListLike
будут продолжать компилироваться, поскольку новые методы имеют стандартную реализацию для ссылочных специальностей (которые просто соединяются с существующими методами удаления). Для экземпляров значенийremoveByIndex
иremoveByValue
рассматриваются как абстрактные и должны быть предоставлены, но удаление вообще не существует.Этот метод также позволяет использовать метод "реализации по частям"; можно объявить абстрактный метод в общем слое и предоставить конкретные реализации как на уровне значений, так и на уровне ссылок. Если бы мы разрешили слои для
T=int
, это также позволило бы использовать технику "специализации специализации".
С помощью этого метода будет сохранена обратная совместимость и будут использоваться новые методы removeByValue
и removeByIndex
.