Введение обобщений в код Java без нарушения сборки - PullRequest
1 голос
/ 13 ноября 2008

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

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?

EDIT

Для уточнения:

У меня есть родовой класс

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 на универсальный формат. Я хотел, чтобы старый код просто выдавал предупреждение вместо ошибки.

Ответы [ 5 ]

12 голосов
/ 13 ноября 2008

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

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);
1 голос
/ 13 ноября 2008

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

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

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

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

1 голос
/ 13 ноября 2008

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

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>> {
    }
}
0 голосов
/ 14 ноября 2008

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

MyList list2 = new MyList ();

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

0 голосов
/ 13 ноября 2008

Вы пробовали:

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

Читайте об этом по адресу: http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html#getClass()

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...