Преобразовать список в StringCollection

Генераторы Java реализуются посредством стирания типа, т. е. аргументы типа используются только для компиляции и компоновки, но стираются для выполнения. То есть, нет соответствия 1: 1 между типами времени компиляции и типами времени выполнения. В частности, все экземпляры родового типа используют один и тот же класс среды выполнения:

new ArrayList<Quod>().getClass() == new ArrayList<String>().getClass();

В системе типа времени компиляции аргументы типа присутствуют и используются для проверки типов. В системе типа времени выполнения аргументы типа отсутствуют и поэтому не проверяются.

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

Как следствие, среда выполнения не может полагаться на правильность аргументов типа. Тем не менее, он должен обеспечить целостность системы типа времени выполнения, чтобы предотвратить повреждение памяти. Это достигается путем задержки проверки типа до тех пор, пока фактическая ссылка не будет использована, и в этот момент среда выполнения знает способ или область, которые она должна поддерживать, и может проверить, что она фактически является экземпляром класса или интерфейса, который объявляет это поле или метод .

С этим вернемся к вашему примеру кода, который я немного упростил (это не меняет поведения):

ArrayList<Quod> test = new ArrayList<Quod>();
ArrayList obj = test; 
obj.add(new Object());
System.out.println(test.get(0));

Объявленный тип obj необработанный тип ArrayList. Необработанные типы отключают проверку аргументов типа во время компиляции. Как следствие, мы можем передать Object в свой метод добавления, хотя ArrayList может содержать только экземпляры Quod в системе типа времени компиляции. То есть мы успешно совладали с компилятором и сделали загрязнение кучи.

Это оставляет систему типа времени выполнения. В системе типа времени выполнения ArrayList работает со ссылками типа Object, поэтому передача Object в метод add в порядке. Так вызывает get(), что также возвращает Object. И вот в чем дело расходится: в вашем первом примере кода у вас есть:

System.out.println(test.get(0));

Тип времени компиляции test.get(0) равен Quod, единственным подходящим методом println является println(Object) и поэтому это подпись метода, встроенная в файл класса. Поэтому во время выполнения мы передаем Object методу println(Object). Это совершенно нормально, и, следовательно, исключение не выбрасывается.

В вашем втором примере кода у вас есть:

System.out.println(test.get(0).toString());

Опять же, тип времени компиляции test.get(0) равен Quod, но теперь мы вызываем его метод toString (). Поэтому компилятор указывает, что метод toString, объявленный в (или унаследованном) типа Quod, должен быть вызван. Очевидно, что этот метод требует, чтобы this указывал на экземпляр Quod, поэтому компилятор добавляет дополнительный бит к Quod в байтовый код перед вызовом метода - и этот бросок бросает ClassCastException.

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

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

13
задан l46kok 17 August 2012 в 18:40
поделиться