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

Вот вопрос, этот первый список кода компилируется просто отлично (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> не имеет никакого отношения к списку (т.е.<E>).

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

Does anyone has any idea why this code does not compile? Does anybody knows any reference where this behavior is documented?
 creemama13 июн. 2012 г., 05:41
Возможный дубликат:stackoverflow.com/questions/1073786.
 creemama13 июн. 2012 г., 05:32
Также интересно, если вы параметризуете с подстановочным знаком,ArrayList<?> a = new ArrayList();ошибка уходит. Кроме того, ошибка исчезнет, еслиInteger используется как тип:ArrayList<Integer> a = new ArrayList();.
 Hovercraft Full Of Eels13 июн. 2012 г., 05:16
Что делать, если вы используете(String[])a.toArray(); Поскольку вы не используете дженерики, кастинг является обязательным.
 Perception13 июн. 2012 г., 05:22
Интересная находка. Как ни странно, если вы явно укажете универсальный параметр как Object (ArrayList & lt; Object & gt;), ошибка исчезнет. Что странно, так как объект должен быть по умолчанию для пропущенных типов.
 Edwin Dalorzo13 июн. 2012 г., 05:19
@HovercraftFullOfEels Спасибо за предложение. Я знаю, что могу разыграть его, но я учусь на сертификацию программиста, и я только что узнал об этом, играя с некоторым универсальным кодом, и не могу объяснить это. Никогда раньше не сталкивался с чем-то подобным. Итак, я больше ищу объяснение того, почему это происходит.

Ответы на вопрос(5)

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

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

Soution via interface inheritence:

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

public interface BaseInterface
{
    String getStringValue();
}

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

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

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

 Edwin Dalorzo13 июн. 2012 г., 05:39
Я ценю ответ, но внутренний массивArrayList  всегда типаObject[] независимо от того, использую я дженерики или нет. Это не влияет на параметризованный метод, когда я использую параметризованныйArrayList  ссылка. Тем не менее, рассматриваемый метод параметризован, ожидаяT[]  как его тип возврата. Почему он игнорируется компилятором, если он не имеет ничего общего с параметризованным типомArrayList? Я до сих пор не вижу связи междуT а такжеE такой, что компилятор ведет себя так.

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

List l = new ArrayList<String>();

Ты используешьraw type и все его элементы экземпляра заменяются его аналогами стирания. Особенноeach параметризованный тип, появляющийся в объявлении метода экземпляра, заменяется его необработанным аналогом. См. JLS 4.8 для деталей.

 13 июн. 2012 г., 05:27
Компилятор знает, объявили ли вы «a»; быть ArrayList или ArrayList & lt; String & gt ;. Это знает это ... ну, глядя на то, что вы написали ... ;-)
 13 июн. 2012 г., 06:51
+1 Очень интересно.
 Edwin Dalorzo13 июн. 2012 г., 05:50
+1 за ссылку JLS.
 Edwin Dalorzo13 июн. 2012 г., 14:48
Если подумать, я считаю, что говорить, что компилятор переходит в режим компиляции 1.4, довольно неточно. Я понимаю, что вы имели в виду, что он обрабатывает ссылку, как если бы она была необработанным типом (как в JDK 1.4, когда не было обобщений), но ваше утверждение можно интерпретировать так, как если бы вы имели в виду, что код скомпилирован, как если бы я передалtarget=1.4 моему компилятору, так как он генерирует 1.4-совместимые байт-коды, что я не считаю нужным. В любом случае, вы можете уточнить, что прежде чем кто-то другой заставит вас заплатить цену с любыми отрицательными голосами ;-)
 Edwin Dalorzo13 июн. 2012 г., 05:24
Как компилятор может сказать, что я не использую обобщенные значения, параметр типа List не имеет ничего общего с параметром типа обобщенного метода toArray?

которое я нашел в спецификации, чтобы описать это наблюдаемое поведение:

The type of a constructor (§8.8), instance method (§8.8, §9.4), or non-static field (§8.3) M of a raw type C that is not inherited from its superclasses or superinterfaces is the erasure of its type in the generic declaration corresponding to C. The type of a static member of a raw type C is the same as its type in the generic declaration corresponding to C.

It is a compile-time error to pass actual type parameters to a non-static type member of a raw type that is not inherited from its superclasses or superinterfaces.

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

The use of raw types is allowed only as a concession to compatibility of legacy code. The use of raw types in code written after the introduction of genericity into the Java programming language is strongly discouraged. It is possible that future versions of the Java programming language will disallow the use of raw types.

 Edwin Dalorzo13 июн. 2012 г., 06:05
+1 для жирной ссылки. Я ценю исследование восприятия. Это определенно проясняет ситуацию для меня.
Решение Вопроса

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

 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):

The type of a constructor (§8.8), instance method (§8.4, §9.4), or non-static field (§8.3) M of a raw type C that is not inherited from its superclasses or superinterfaces is the raw type that corresponds to the erasure of its type in the generic declaration corresponding to C.

 Edwin Dalorzo13 июн. 2012 г., 05:49
@MarkPeters Удивительно, это то, что я искал. б (^_^) д
 13 июн. 2012 г., 05:43
@ Эдвин Далорсо - см. Мой отредактированный ответ - JLS 4.8
 Edwin Dalorzo13 июн. 2012 г., 05:41
+1 Похоже, что компилятор намекает на использование необработанного типа и отключает любые родовые типы оттуда в данной ссылке. Хм, интересно. Интересно, задокументировано ли это в JLS. Вы случайно не знаете?
 13 июн. 2012 г., 05:46
@ Эдвин: Я процитировал это в своем ответе, похоже, что Премрай тоже его нашел.

Ваш ответ на вопрос