我有这些课程:
public class A <T>{
}
public interface I {
}
public class X implements I {
}
public class B extends A<X>{
}
Run Code Online (Sandbox Code Playgroud)
在我的代码中如果我这样做我得到错误:
A<I> myobj = (A<I>) new B();
Run Code Online (Sandbox Code Playgroud)
肯定是:
A<X> myobj = (A<X>) new B();
Run Code Online (Sandbox Code Playgroud)
但是,如果我这样做是好的,并且效果很好:
A<I> myobj = null;
myobj = (A<I>) Class.forName("B").newInstance();
Run Code Online (Sandbox Code Playgroud)
在最后一种情况下,我访问B的所有方法,并且工作得很好.
我需要将myobj声明为A,因为我只保证泛型obj的接口而不是具体的类.
有谁知道为什么我的第一个案例不起作用?
我想实现第一个应该是最优雅的.
这是泛型在Java中的工作方式.Class String实现接口CharSequence,但是不能将List <CharSequence>转换为List <String>(反之亦然).但是您可以将ArrayList <String>转换为List <String>(并将List <String>转换为ArrayList <String> - 至少编译器不会抱怨,但如果List对象不是实例,您将获得运行时异常of 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!
Run Code Online (Sandbox Code Playgroud)
这就是第2行出现编译错误的原因.当然,你可以欺骗编译器并试试这个:
A<I> myobj = null;
A genericA = new B();
myobj = (A<I>) genericA;
Run Code Online (Sandbox Code Playgroud)
这将起作用,因为在运行时中删除了泛型类型.您也可以使用列表执行此操作:
List<String> listOfStrings = new ArrayList<String>();
List genericList = listOfStrings;
genericList.add(new Object());
String s = listOfStrings.get(0);
Run Code Online (Sandbox Code Playgroud)
此代码将编译(带警告),但您将在运行时获得异常:
Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String
Run Code Online (Sandbox Code Playgroud)
这段代码:
myobj = (A<I>) Class.forName("B").newInstance();
Run Code Online (Sandbox Code Playgroud)
因为newInstance()方法返回java.lang.Object的一个实例.编译器不知道它将在运行时返回什么,因此它允许将其转换为所有内容.由于类型擦除,在运行时A <I>只是A,并且由于B是A的子类,因此可以将B的实例强制转换为A.