2013-04-04 6 views
1

У меня есть эти классы:Странная ошибка отлитый в Java

public class A <T>{ 
} 

public interface I {  
} 

public class X implements I { 
} 

public class B extends A<X>{ 
} 

В моем коде, если я делаю это я получаю ошибку:

A<I> myobj = (A<I>) new B(); 

Оно должно быть:

A<X> myobj = (A<X>) new B(); 

Но если я это сделаю, это нормально и хорошо работает:

A<I> myobj = null; 
myobj = (A<I>) Class.forName("B").newInstance(); 

В этом последнем случае я обращаюсь ко всем методам B и работает очень хорошо.

Мне нужно объявить myobj как A, потому что я гарантирую только интерфейс общих объектов, а не класса.

Кто-нибудь знает, почему мой первый случай не работает?

Я бы хотел, чтобы первый из них был самым элегантным.

+1

http://stackoverflow.com/questions/2745265/ is-listdog-a-subclass-of-listanimal-why-arent-javas-generics-implicit – assylias

+2

cast to A вместо A

+0

Спасибо всем A хорошо работает, и мой код стал более элегантным :).Но я до сих пор смущен последним случаем :( – Heberfa

ответ

5

Это то, как дженерики работают на Java. Класс String реализует интерфейс CharSequence, но вы не можете использовать List <CharSequence> для списка <String> (или наоборот). Но вы можете бросить ArrayList < Строки > к списку < Строки > (и список < Строки > для ArrayList < Строки > - по крайней мере, компилятор не будет жаловаться, но вы получите исключение во время выполнения, если ваш объект списка не является экземпляр от ArrayList).

Что делать, если это возможно? Вот пример:

1. List<String> listOfStrings = new ArrayList<String>(); // piece of cake! 
2. List<Object> listOfObjects = (List<Object>) listOfString; // String is a subclass ofObject, so why not? 
3. listOfObjects.add(new Object()); // obviously correct 
4. String s = listOfString.get(0); // ouch! We've just put an Object into this list, but generic type promises there are only Strings! 

Вот почему есть ошибка компиляции в строке 2. Конечно, вы можете обмануть компилятор и попробовать это:

A<I> myobj = null; 
A genericA = new B(); 
myobj = (A<I>) genericA; 

Это будет работать, потому что общие типы удаляются в время выполнения. Вы можете сделать это также со списками:

List<String> listOfStrings = new ArrayList<String>(); 
List genericList = listOfStrings; 
genericList.add(new Object()); 
String s = listOfStrings.get(0); 

Этот код компилируется (с предупреждениями), но вы получите исключение во время выполнения:

Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String 

Этот код:

myobj = (A<I>) Class.forName("B").newInstance(); 

работает, потому что метод newInstance() возвращает экземпляр java.lang.Object. Компилятор понятия не имеет, что он будет возвращать во время выполнения, поэтому он позволяет бросать его на все. Из-за Type Erasure во время выполнения A <I> является просто A, а так как B является подклассом A, вы можете отличить экземпляр от B до A.

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