Какова концепция стирания в дженериках в Java?

 **Try this code for parsing json data**      

               ArrayList> list;
              JSONObject jsonObj = new JSONObject(jsonStr);

               // Getting JSON Array node
               JSONArray b= jsonObj.getJSONArray("methodClass");

               // looping through All data
               for (int i = 0; i < b.length(); i++) {
                  JSONObject c = b.getJSONObject(i);

                  String entrymethodName = c.getJSONObject("methodClass").getString("methodName");
                  String entrymethodStatus = c.getJSONObject("methodClass").getString("methodStatus");

                  // tmp hash map for storing values
                  HashMap co = new HashMap<>();

                  // adding each child node to HashMap key => value
                  co.put(entrymethodName, entrymethodStatus );


                  // adding co to  list
                  list.add(co);

Также проверьте это - https://gist.github.com/codebutler/2339666

138
задан Peter Mortensen 27 September 2015 в 08:04
поделиться

5 ответов

Это - в основном способ, которым дженерики реализованы в Java через обман компилятора. Скомпилированный общий код на самом деле просто использует java.lang.Object везде, где Вы говорите о T (или некоторый другой параметр типа) - и существуют некоторые метаданные, чтобы сказать компилятору, что это действительно - универсальный тип.

При компиляции некоторого кода против универсального типа или метода компилятор разрабатывает то, что Вы действительно имеете в виду (т.е. что аргумент типа для T ), и проверяет во время компиляции, что Вы делаете правильную вещь, но испускаемый код снова просто говорит с точки зрения java.lang.Object - компилятор генерирует дополнительные броски в случае необходимости. Во время выполнения, a List<String> и a List<Date> точно то же; дополнительная информация о типе была стерта компилятором.

Сравните это с, скажем, C#, где информация сохраняется во время выполнения, позволяя коду содержать выражения такой как typeof(T) который является эквивалентом T.class - за исключением того, что последний недопустим. (Существуют дальнейшие различия между дженериками.NET и дженериками Java, заметьте.) Стирание типа является источником многих из "нечетного" предупреждения/сообщений об ошибках при контакте с дженериками Java.

Другие ресурсы:

195
ответ дан 23 November 2019 в 23:27
поделиться

Насколько я понимаю (будучи парнем.NET) JVM не имеет никакого понятия дженериков, таким образом, параметры типа замен компилятора с Объектом и выполняют весь кастинг для Вас.

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

5
ответ дан 23 November 2019 в 23:27
поделиться

Дополнение уже дополненного ответа Jon Skeet...

Было упомянуто, что реализация дженериков через стирание приводит к некоторым раздражающим ограничениям (например, нет new T[42]). Было также упомянуто, что основная причина того, чтобы сделать вещи этот путь была назад совместимостью в байт-коде. Это также (главным образом) верно. Сгенерированный байт-код - предназначается 1.5, несколько отличается от просто de-sugared бросающий - предназначаются 1.4. Технически, даже возможно (посредством огромного обмана) получить доступ к универсальным инстанцированиям типа во времени выполнения, доказывая, что действительно существует что-то в байт-коде.

Более интересный момент (который не был повышен) - то, что реализация дженериков с помощью стирания предлагает вполне немного больше гибкости в том, что может выполнить высокоуровневая система типов. Хорошим примером этого была бы реализация JVM Scala по сравнению с CLR. На JVM возможно реализовать более высокие виды непосредственно вследствие того, что сама JVM не вводит ограничений для универсальных типов (так как эти "типы" эффективно отсутствуют). Это контрастирует с CLR, который имеет знание во время выполнения инстанцирований параметра. Из-за этого сам CLR должен иметь некоторое понятие того, как дженерики должны использоваться, аннулируя попытки расширить систему с помощью непредвиденных правил. В результате более высокие виды Scala на CLR реализованы с помощью странной формы стирания, эмулированного в рамках самого компилятора, делая их не полностью совместимыми с простыми дженериками.NET.

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

8
ответ дан 23 November 2019 в 23:27
поделиться

Для завершения ответа уже очень полного Jon Skeet необходимо понять, что понятие стирания типа происходит из потребности совместимости с предыдущими версиями Java.

Первоначально представленный в EclipseCon 2007 (больше не доступный), совместимость включала те точки:

  • Исходная совместимость (Хороший, чтобы иметь...)
  • Совместимость на уровне двоичных кодов (Должен иметь!)
  • Совместимость миграции
    • Существующие программы должны продолжить работать
    • Существующие библиотеки должны смочь использовать универсальные типы
    • Должен иметь!

Исходный ответ:

Следовательно:

new ArrayList<String>() => new ArrayList()

Существуют суждения для большей материализации. Овеществите быть "Отношением абстрактное понятие как реальное", где конструкции языка должны быть понятиями, не только синтаксическим сахаром.

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

Механизм дженериков на языке предоставляет времени компиляции (статическую) проверку типа, но возможно победить этот механизм с бросками непроверенными.

Обычно это не проблема, поскольку компилятор выдает предупреждения на всех таких операциях непроверенных.

Существуют, однако, времена, когда одна только статическая проверка типа не достаточна, как:

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

Июль 2012 обновления, почти четыре года спустя:

Это теперь (2012) подробно в "Правилах Совместимости Миграции API (Тест Подписи)"

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

Для упрощения взаимодействия через интерфейс с неуниверсальным унаследованным кодом также возможно использовать стирание параметризованного типа как тип. Такой тип называют необработанным типом (Спецификация языка 3/4.8 Java). Разрешение необработанного типа также гарантирует обратную совместимость для исходного кода.

Согласно этому, следующим версиям java.util.Iterator класс является и двоичным и обратно совместимым исходным кодом:

Class java.util.Iterator as it is defined in Java SE version 1.4:

public interface Iterator {
    boolean hasNext();
    Object next();
    void remove();
}

Class java.util.Iterator as it is defined in Java SE version 5.0:

public interface Iterator<E> {
    boolean hasNext();
    E next();
    void remove();
}
25
ответ дан 23 November 2019 в 23:27
поделиться

Как примечание, это интересное упражнение, чтобы на самом деле посмотреть, что делает компилятор, когда он выполняет стирание, - это немного упрощает понимание всей концепции. Существует специальный флаг, который вы можете передать компилятору для вывода файлов java, в которых были стерты общие шаблоны и вставлены приведенные типы. Пример:

javac -XD-printflat -d output_dir SomeFile.java

-printflat - это флаг, который передается компилятору, который генерирует файлы. (Часть -XD - это то, что сообщает javac передать его исполняемому jar-файлу, который фактически выполняет компиляцию, а не просто javac , но я отвлекся ... ) -d output_dir необходим, потому что компилятору нужно место для размещения новых файлов .java.

Это, конечно, больше, чем просто стирание; здесь выполняется вся автоматическая работа компилятора. Например, также вставляются конструкторы по умолчанию, новые циклы в стиле foreach для расширяются до обычных циклов для и т.д. Приятно видеть мелочи, которые происходят автоматически.

здесь выполняется вся автоматическая работа компилятора. Например, также вставляются конструкторы по умолчанию, новые циклы в стиле foreach для расширяются до обычных циклов для и т.д. Приятно видеть мелочи, которые происходят автоматически.

здесь выполняется вся автоматическая работа компилятора. Например, также вставляются конструкторы по умолчанию, новые циклы в стиле foreach для расширяются до обычных циклов для и т.д. Приятно видеть мелочи, которые происходят автоматически.

40
ответ дан 23 November 2019 в 23:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: