Что такое овеществленные дженерики? Как они решают проблемы стирания типов и почему их нельзя добавить без серьезных изменений?

Я читал Нил Гэфтер это блог на эту тему и до сих пор неясно по ряду моментов.

почему невозможно создать реализации API коллекций, которые сохраняют информацию о типе, учитывая текущее состояние Java, JVM и существующего API коллекций? Не могли бы они заменить существующие реализации в будущей версии Java таким образом, где сохраняется обратная совместимость?

Как пример:

List<T> list = REIList<T>(T.Class);

где Рейлист что-то вроде этого:

public REIList<T>() implements List {
  private Object o;
  private Class klass;

  public REIList(Object o) {
    this.o = o;
    klass = o.getClass();
  }
... the rest of the list implementation ...

и методы используют Object o и Class klass для получения информации о типе.

почему сохранение общей информации о классе требует языковых изменений, а не просто изменения реализации JVM?

чего я не понимаю?

4 ответов


все дело в том, что у reified generics есть поддержка в компиляторе для сохранения информации о типе, тогда как тип erased generics нет. AFAIK, весь смысл стирания типа в первую очередь состоял в том, чтобы включить обратную совместимость (например, более низкие версии JVMs все еще могли понимать общие классы).

вы можете явно добавить информацию о типе в реализацию, как указано выше, но для этого требуется дополнительный код каждый раз, когда используется список, и довольно грязно, на мой взгляд. Кроме того, в этом случае у вас все еще нет проверки типа среды выполнения для всех методов списка, если вы не добавляете проверки самостоятельно, однако reified generics обеспечит типы среды выполнения.


вопреки убеждениям большинства разработчиков Java, можно сохранить информацию о типе времени компиляции и получить эту информацию во время выполнения, Несмотря на очень ограниченный способ. Другими словами: Java предоставляет овеществленные дженерики очень ограниченным способом.

по поводу стирания типа

обратите внимание, что, во время компиляции, компилятор имеет полную информацию, но эта информация умышленно за в общем когда двоичный код генерируется, в процессе, известном как стирания типа. Это делается таким образом из-за проблем совместимости: намерение языковых дизайнеров обеспечивало полную совместимость исходного кода и полную совместимость двоичного кода между версиями платформы. Если бы он был реализован по-другому, вам пришлось бы перекомпилировать устаревшие приложения при переходе на более новые версии платформы. Как это было сделано, все сигнатуры методов сохраняются (исходный код совместимость), и вам не нужно ничего перекомпилировать (двоичная совместимость).

относительно овеществленных дженериков в Java

Если вам нужно сохранить информацию о типе времени компиляции, вам нужно использовать анонимные классы. Дело в том, что в очень частном случае анонимных классов можно получить полную информацию о типе времени компиляции во время выполнения, что, другими словами, означает: reified generics.

Я написал статью об этом тема:

http://rgomes-info.blogspot.co.uk/2013/12/using-typetokens-to-retrieve-generic.html

в статье я описываю, как наши пользователи отнеслись к технике. В двух словах, это неясная тема, и техника (или шаблон, если хотите) выглядит посторонней для большинства разработчиков Java.

пример кода

в статье, о которой я упоминал выше, есть ссылки на исходный код, который реализует эту идею.


IIRC (и на основе ссылки), Java generics-это просто синтаксический сахар для существующей техники использования коллекции объектов и литья туда и обратно. Безопаснее и проще использовать Java generics, так как компилятор может выполнять проверки для вас, чтобы убедиться, что вы поддерживаете compileбезопасность типов времени. Время выполнения, однако, совершенно другая проблема.

.NET generics, с другой стороны, фактически создают новые типы - A List<String> в C# это другой тип чем List<Int>. В Java, под обложками, они то же самое - a List<Object>. Это означает, что если у вас есть один из них, вы не можете смотреть на них во время выполнения и видеть, как они были объявлены - только то, что они есть сейчас.

овеществленные дженерики изменят это, предоставив разработчикам Java те же возможности, которые существуют сейчас .Сеть.


Я не эксперт по теме, но как я понимаю информация о типе теряется во время компиляции. В отличие от C++, Java не использует систему шаблонов, безопасность типов достигается полностью через компилятор. Во время выполнения список на самом деле является списком, всегда.

поэтому я считаю, что изменение спецификации языка требуется из-за того, что информация о типе недоступна для JVM потому что его не существует.