Пытаясь понять дженерики - PullRequest
       14

Пытаясь понять дженерики

0 голосов
/ 23 февраля 2012

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

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 = new ArrayList ();'и тот же самый случай даже из вызова метода return even.

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

Ответы [ 6 ]

1 голос
/ 23 февраля 2012

В связи с тем, как реализованы универсальные шаблоны Java (см. Тип Erasure для ознакомительного объяснения), можно создавать экземпляры необработанных типов универсальных классов и затем приводить их к универсальной версии, как вназначения на iList.Это приводит к предупреждению компилятора, так как это потенциально небезопасная операция.Вы можете добавить любой тип, который вам нравится, в необработанный ArrayList (он эквивалентен ArrayList), но если вы затем приведете его к более конкретному универсальному типу, у вас может быть несовместимая коллекция.список в returList.Однако ваш код не демонстрирует это, поскольку println() не зависит от типа переданного ему элемента списка.Добавьте строку, такую ​​как

Integer val = iList.get(i);

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

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

1 голос
/ 23 февраля 2012

Прочитайте это: http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf, рекомендуется два или три раза.

1 голос
/ 23 февраля 2012

Обобщения были созданы в качестве помощи разработчику, но вы должны использовать их, чтобы получить выгоду.Ваша 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 голосов
/ 23 февраля 2012

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

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

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

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

Подробнее см. http://docs.oracle.com/javase/tutorial/java/generics/erasure.html.

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

0 голосов
/ 23 февраля 2012

Здесь ответили здесь :

Почему разрешены необработанные типы?

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

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

0 голосов
/ 23 февраля 2012

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

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. Программирование на интерфейсах
  2. Избегайте ненужных инициализаций
  3. Используйте типпараметры реализации также (RHS оператора присваивания)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...