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


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

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

Как пример:

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

где REIList что-то вроде этого:

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 ...

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

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

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

4 59

4 ответа:

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

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

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

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

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

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

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

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

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 те же возможности, которые существуют сейчас в. NET.

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

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