Подтвердить что ты не робот

Объединение сырых типов и общих методов

Здесь вопрос, этот первый список кодов компилируется просто отлично (JDK 1.6 | JDK 1.7):

ArrayList<String> a = new ArrayList<String>();
String[] s = a.toArray(new String[0]);

Однако, если я объявляю ссылку List как необработанный тип:

ArrayList a = new ArrayList();
String[] s = a.toArray(new String[0]);

Я получаю ошибку компилятора, если требуется String[], но найдено Object[].

Это означает, что мой компилятор интерпретирует общий метод как возвращающий Object[], несмотря на получение в качестве аргумента String[].

Я дважды проверял подпись метода toArray(myArray):

<T> T[] toArray(T[] a);

Следовательно, это параметризованный метод, параметр типа <T> не имеет никакого отношения к классу List (т.е. <E>).

Я понятия не имею, как использование необработанного типа влияет на оценку параметризованных методов с использованием независимых параметров типа.

  • Кто-нибудь знает, почему этот код не компилируется?
  • Кто-нибудь знает какую-либо ссылку, где это поведение документировано?
4b9b3361

Ответ 1

Это не совсем то, что вы ожидаете, но если вы ссылаетесь на общий класс в необработанном виде, вы теряете возможность использовать дженерики каким-либо образом, например, для членов. Это также не ограничивается общими методами, проверьте это:

 public class MyContainer<T> {

     public List<String> strings() {
         return Arrays.asList("a", "b");
     }
 }

 MyContainer container = new MyContainer<Integer>();
 List<String> strings = container.strings(); //gives unchecked warning!

Это соответствующая часть JLS (4.8):

Тип конструктора (§8.8), метод экземпляра (§8.4, п. 9.4) или нестатического поля (§8.3) М необработанного типа С, который не унаследован от его суперклассов или суперинтерфейсов, является исходным тип, соответствующий стиранию его типа в общем объявлении, соответствующем C.

Ответ 2

Это самое близкое описание, которое я нашел в спецификации для описания этого наблюдаемого поведения:

Тип конструктора (§8.8), метод экземпляра (§8.8, п. 9.4) или нестатического поля (§8.3) M необработанного типа C, который не унаследован от его суперклассы или суперинтерфейсы - это стирание своего типа в общая декларация, соответствующая C. Тип статического члена необработанный тип C такой же, как и его тип, в общей декларации соответствующий C.

Это ошибка времени компиляции для передачи параметров фактического типа в нестатический член типа необработанного типа, который не унаследован от его суперклассов или суперинтерфейсов.

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

Использование типов raw допускается только в качестве концессии на совместимость устаревшего кода. Использование исходных типов в коде, написанном после введение универсальности в язык программирования Java сильно обескуражен. Возможно, что будущие версии Java язык программирования запретит использование исходных типов.

Ответ 3

Если вы не используете generics, компилятор рассматривает его как необработанный тип, и поэтому каждый родовой тип становится Object, и поэтому вы не можете передать String[], потому что ему нужно Object[]
Итак, вот сделка - Если вы используете

List l = new ArrayList<String>();

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

Ответ 4

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

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

Soution через наследование интерфейса:

public interface GenericInterface<X extends Y> extends BaseInterface
{
    X getValue();
}

public interface BaseInterface
{
    String getStringValue();
}

Теперь вы можете делать следующее без предупреждения или проблем:

GenericInterface object = ...;
String stringValue = object.getStringValue();

Ответ 5

Не может быть никакого параметра типа, переданного в метод toArray(), так как ваш ArrayList является непараметрированным списком, он знает только, что он содержит объекты, что он. a.toArray() всегда будет возвращать массив Object []. Опять же, вы должны указать его на (String[]) (со всеми опасностями), если вы хотите указать, что он содержит определенный тип строки.