Я получаю исключение ClassCast, когда я перечисляю вектор с параметром типа String, но исключение не существует с параметром типа Integer

Я пробовал свои руки на векторах и написал простой код для доступа к его элементам через перечисление.

Vector v = new Vector();
    v.add("Some String");
    v.add(10);

    Enumeration e = v.elements();
    while(e.hasMoreElements()) System.out.println(e.nextElement());

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

С параметром типа String:

Vector v = new Vector();
    v.add("Some String");
    v.add(10);

    Enumeration<String> e = v.elements();
    while(e.hasMoreElements()) System.out.println(e.nextElement());

Вывод:

Некоторая строка

Исключение в потоке "main" java.lang.ClassCastException: java.lang.Integer нельзя передать в java.lang.String

С параметром типа Integer:

Vector v = new Vector();
    v.add("Some String");
    v.add(10);

    Enumeration<Integer> e = v.elements();
    while(e.hasMoreElements()) System.out.println(e.nextElement());

Вывод:

Некоторая строка

10

Что здесь происходит? Не должны ли оба случая вызывать исключение ClassCast?

Ответ 1

Обратите внимание, что все обобщения стираются при компиляции, а просто помочь компилятору подтвердить, что вы не допустили ошибок. Вероятно, вы получаете несколько предупреждений в этом пункте, говоря, что вам не следует использовать необработанные типы (исходные значения Vector вместо Vector<String> и т.д.). Общий эквивалент типа raw <?> указывает, что вы разрешите любой тип (обратите внимание, что это приведет к тому, что код больше не будет компилятором).

Поведение, которое вы видите, состоит в том, что есть два (на самом деле еще несколько, но в вашем случае два) функции с именем System.out.println() и разными типами параметров, это называется (перегрузка метода):

  • System.out.println(String)
  • System.out.println(объект)

В момент компиляции решено, что вызывается для вашего кода.

В примере String перечисление имеет общий тип String и вызовет первый. Однако, когда он получает объект Integer из вашего Vector, это приводит к сбою при передаче его в String. Поэтому в этом случае компилятор преобразует ваш код в следующий (примерно):

Enumeration e = v.elements();
while(e.hasMoreElements()) System.out.println((String)e.nextElement());

В примере Integer перечисление имеет общий тип Integer, который будет отображаться в System.out.println(Object), который принимает как String, так и Integer, поэтому все идет хорошо.

На стороне: по умолчанию вы должны использовать ArrayList вместо Vector, у него есть более чистый интерфейс из-за унаследованных методов в Vector. Также Vector синхронизируется, вызывая ненужные служебные данные.