Введение дженериков в код Java без нарушения сборки

Следующий код не компилируется:

public class GenericsTest {    
    public static void main(String[] args) {
        MyList<?> list = new MyList<Object>();
        Class<?> clazz = list.get(0);

        // Does not compile with reason 
        // "Type mismatch: cannot convert from Object to Class"
        MyList list2 = new MyList();
        Class clazz2 = list2.get(0);
    }
    static class MyList<T> extends ArrayList<Class<T>> {
    }
}

Я хотел сделать это, чтобы внедрить дженерики в старый код без нарушения сборки.

Это ошибка как компилятора (как eclipse, так и javac), или мне что-то здесь не хватает? Какая еще возможность существует для введения дженериков в MyList?

РЕДАКТИРОВАТЬ

В целях разъяснения:

У меня есть общий класс

public class MyList extends ArrayList<MyObject> {}

с

public class MyObject {}

и код с использованием MyList

MyList list = new MyList();
...
MyObject o = list.get(0);

Теперь, во время разработки, я вижу, что хочу добавить дженерики в MyObject.

public class MyObject<T> {}

и теперь я хочу, чтобы эта новая общая штука была в MyList

public class MyList<T> extends ArrayList<MyObject<T>> {}

Но это ломает мою сборку. интересно

public class MyList<T> extends ArrayList<MyObject<T>> {
    public MyObject<T> get(int i) {
        return super.get(i);
    }
}

позволит старый код

MyList list = new MyList();
...
MyObject o = list.get(0);

компилировать.

Хорошо, кажется, что когда я представлю этот общий, мне придется смириться с необходимостью изменить все вызовы MyList на универсальную форму. Я хотел, чтобы старый код просто выводил предупреждение вместо ошибки.

Было бы полезно, если бы вы указали ошибку компиляции, а также код.

Herms 13.11.2008 19:34

Ошибка компиляции находится в комментарии к образцу.

Tobias Schulte 13.11.2008 20:00
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
2
548
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Ты пробовала:

Class clazz2 = list2.get(0).getClass();

Об этом читайте здесь: http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html#getClass ()

Но это не то же самое! String.class! = String.class.getClass ()

Tobias Schulte 13.11.2008 19:58
Ответ принят как подходящий

Я думаю, вы не совсем понимаете, как работают дженерики.

MyList<?> list = new MyList<Object>();
Class<String> clazz= list.get(0);

Этот фрагмент кода не компилируется, потому что вы сообщаете компилятору, что list будет содержать типы Class<Object>, а затем в следующей строке вы ожидаете, что он вернет вам Class<String>. Универсальная система в Java не способна преобразовывать типы, используемые с универсальными шаблонами, на основе наследования, как вы могли бы подумать.

Если вы ожидаете, что list будет содержать Class<String>, вам нужно объявить его так, или, если вы хотите, чтобы он мог содержать любые типы, вы не можете выполнить вторую строку без приведения.

MyList<String> list = new MyList<String>();
Class<String> clazz = list.get(0);

или же

MyList<?> list = new MyList<Object>();
//generates a warning about an unchecked cast
Class<String> clazz = (Class<String>) list.get(0);

Второй фрагмент кода не работает, потому что, когда вы используете необработанные типы, вам все равно нужно привести Object, возвращаемый get(), к объявленному типу, который вы используете (что всегда имело место).

MyList list2 = new MyList();
Class clazz2 = (Class) list2.get(0);

Я думаю, вы не видели объявление класса MyList в конце: статический класс MyList <T> расширяет ArrayList <Class <T>>. Определено, что MyList <T> принимает Class <T> -Objects.

Mnementh 13.11.2008 19:39

Верно, я уловил это в конце, но он ожидает, что MyList <Object> будет преобразован в MyList <String>, а это не так.

matt b 13.11.2008 19:41

Нет, я не ожидаю, что MyList <Object> можно будет преобразовать в MyList <String>. Я хочу, чтобы MyList можно было преобразовать в MyList <?>. Извините, в моем примере произошла ошибка.

Tobias Schulte 13.11.2008 20:11

Что ж, с вашим исправленным примером мой второй ответ все еще применим - метод get () в необработанном списке возвращает объект, поэтому вам нужно явно привести его к классу.

matt b 13.11.2008 22:28

У меня нет компилятора на этой машине, но он должен работать.

public class GenericsTest {    
    public static void main(String[] args) {
        MyList<Object> list = new MyList<Object>();
        Class<?> clazz= list.get(0);

    }


    static class MyList<T> extends ArrayList<Class<? extends T>> {
    }
}

Да, это так. Существует ошибка времени выполнения, поскольку он вызывает get () в пустом списке, но код компилируется.

Julien Grenier 14.11.2008 07:01

Да, ваш код компилируется, но не "Class clazz = list.get (0);" ни "MyList <String> list = new MyList <String> (); Class <String> clazz = list.get (0);". «Класс <? Extends String> clazz = list.get (0);» будет работать, но не по назначению.

Tobias Schulte 14.11.2008 11:22

В вашем примере MyList - это старый код, который вы хотите обновить для поддержки дженериков? Если да, то какой тип объектов должен содержать мой список?

Как упоминалось здесь в другом месте, ошибка компиляции действительна. Это связано с тем, что доступ к необработанному списку осуществляется без преобразования get в Class. Следовательно, код пытается назначить объект ссылке на класс. Это эквивалентно этому:

Object o = new Object();
Class c = o;

Которая просто не может скомпилироваться. Кроме того, чтобы в полной мере использовать дженерики, вы должны отдавать предпочтение Class <?> Вместо Class.

В вашем примере второй пример не работает, потому что вы не используете дженерики, поэтому это означает, что метод get () вернет объект, и вам нужно будет преобразовать его в класс. Если вы не указываете тип своего MyList:

MyList list2 = new MyList();

Тогда вы теряете преимущества Generics, и вам нужно приводить объект при вызове метода get (), как в старые добрые времена.

Другие вопросы по теме