Java中的奇怪转换错误

时间:2013-04-04 18:56:49

标签: java generics

我有这些课程:

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,因为我只保证泛型obj的接口而不是特定的类。

任何人都知道为什么我的第一个案例不起作用?

我想实现第一个应该是最优雅的。

1 个答案:

答案 0 :(得分:5)

这是泛型在Java中的工作方式。 Class String实现接口CharSequence,但是你不能转换List&lt; CharSequence&gt;列出&lt; String&gt; (或相反亦然)。但是你可以转换ArrayList&lt; String&gt;列出&lt; String&gt; (和List&lt; String&gt;到ArrayList&lt; String&gt; - 至少编译器不会抱怨,但如果List对象不是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&lt; I&gt;中。只是A,由于B是A的子类,因此可以将B的实例强制转换为A。