2012-02-23 3 views
0

У меня есть следующий фрагмент кодаПытаясь понять Generics

public static void main(String[] args) { 
     ArrayList<Integer> iList = new ArrayList(); 
     iList = returList(); 
     for (int i = 0; i < iList.size(); i++) { 
      System.out.println(iList.get(i)); 
     } 
    } 

    public static ArrayList returList() { 
     ArrayList al = new ArrayList(); 
     al.add("S"); 
     al.add(1); 
     return al; 
    } 

теперь мой вопрос почему Список_массивы принимают создание объекта сырой ArrayList в строке «ArrayList IList = новый ArrayList();» и тот же случай даже из метода call return even.

Теперь, какой тип данных будет там, и будет ли это подразумевать Generics? я не вижу ошибок компиляции, и этот код работает нормально.

+1

См: http://stackoverflow.com/questions/490091/java-generics – Matthias

+0

@adarshr означает, что вы должны отметить правильный ответ, когда вы найдете его –

ответ

1

Из-за реализации Java-дженериков (см. Type Erasure для вводного объяснения) можно создать экземпляры «сырого» типа общих классов, а затем передать их в общую версию, как и в ваших назначениях, до iList. Это приводит к предупреждению компилятора, поскольку это потенциально опасная операция. Вы можете добавить любой тип, который вам нравится, к необработанному массиву ArrayList (он эквивалентен ArrayList), но если вы затем примените его к более определенному родовому типу, у вас может быть непоследовательная коллекция.

В вашем примере вы создали такой список в returList. Однако ваш код не показывает это, поскольку println() не полагается на тип переданного ему элемента списка. Добавьте строку, такие как

Integer val = iList.get(i); 

к вашему for цикла и запустить свой код и вы получите ClassCastException ваша программа пытается бросить строку "s" к Integer.

Когда общая коллекция несовместима, вы не узнаете, пока не попытаетесь получить доступ к непоследовательным элементам, используя общий тип.

0

Потому что это неправильно. Это так, как это сделано правильно:

public static void main(String[] args) { 
    List<Integer> iList = returList(); 
    for (int i = 0; i < iList.size(); i++) { 
     System.out.println(iList.get(i)); 
    } 
} 

public static List<Integer> returList() { 
    List<Integer> al = new ArrayList<Integer>(); 
    //al.add("S"); This line can't compile now! 
    al.add(1); 
    return al; 
} 

Очки отметить:

  1. Programing против интерфейсов
  2. Избегайте ненужные инициализации
  3. Используйте параметры типа по реализации, а также (RHS оператора присваивания)
+0

, что будет эта строка кода налагают Теперь «ArrayList IList = новый ArrayList();» – Shiv

+0

необработанный arraylist? – Shiv

+0

Эта строка кода даст вам предупреждение, как показано в ответе @ Perception. – adarshr

1

Дженерики были созданы в качестве помощи разработчику, но у вас есть использовать их для того, чтобы извлечь выгоду. Ваш IDE будет предостерегал вас от необработанного использования ArrayList:

ArrayList is a raw type. References to generic type ArrayList<E> should be parameterized 

Но это не мешает вам висит себя, нет. Обратите внимание, что в некоторых IDE вы можете заставить их компилировать ошибки, которые могут быть тем, что вы ищете.

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

public static void main(String[] args) { 
     ArrayList<Integer> iList = new ArrayList(); 
     iList = returList(); 
     for (final Integer i: iList) { 
      System.out.println(i.intValue()); 
     } 
} 
+0

Это имело смысл. но не совсем то, что я искал. – Shiv

+0

@ Шиваджи - не уверен, что не имеет смысла. Но я добавил более подробно ваш второй вопрос. – Perception

+0

Ях я вижу какие-то странные вещи здесь .. я просто изменил мой код, как это государственной статической силы основных (String [] арг) { \t \t ArrayList IList; // = новый ArrayList(); \t \t iList = returList(); \t \t для (INT I = 0; г "); \t \t \t System.out.println (iList.get (i) .getClass()); \t \t} } и теперь я вижу странные результаты .. класс caste исключение. Было действительно невозможно разобраться в этом. Не могли бы вы мне немного объяснить? – Shiv

0

Это отвечает here:

Почему сырые типы разрешается?

Сырые типы разрешается на языке преимущественно для облегчения взаимодействия с необщего (унаследованных) кода.

Если, например, у вас есть универсальный унаследованный метод, который принимает список как аргумент , вы можете передать параметризованный тип, такой как List to , этот метод. И наоборот, если у вас есть метод, который возвращает List, , вы можете присвоить результат ссылочной переменной типа List , если вам почему-то известно, что вернувшийся список действительно представляет собой список строк .

+0

Итак, шансы потерять контекст генетики вступают в действие, не так ли? – Shiv

+0

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

0

Немного истории дженериков может помочь объяснить некоторые странности.

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

У этого есть досадные последствия, когда вы не можете полагаться на типы, как показано в вашем исходном коде.

Это то, что происходит в вашем примере.

Для получения более подробной информации см. http://docs.oracle.com/javase/tutorial/java/generics/erasure.html.

Обратите внимание, что для Java 5 формат .class был в конечном итоге изменен для обеспечения автоматического бокса. Тот факт, что формат класса менялся, что позволяет делать дженерики должным образом, не использовалось из-за ограничений по времени.

Смежные вопросы