以下都是错误的。问题是我对运行时泛型擦除机制理解不够,太low。
Pair<Employee> pair
List<String> list = new ArrayList<String>();
这里给List设置String,能在编译阶段起到检查的功能,也就是如果如下,编译的时候会报错。
list.add(100)
但是一旦通过编译到了运行阶段,泛型String会被擦除,就没有String 之分了,只有一个单纯的List。
更进一步说,什么能够在编译阶段检查出来呢?
就如同上面,代码调用含泛型参数的接口,传入一个参数,会对这个参数的类型进行检查。但是别指望运行期间给你做什么了。
但是对于工作代码,就要谨慎了。比如方法中有一句代码是这样的:
T t =(T)obj;
那么实际的情况,这就没有作用,类型强转发生在代码运行中的。在class文件的形式就是:
Object t = (Object) obj;
记住这种实例方式
List<String> list = new ArrayList<String>();
到了Class那里就变成
List list = new ArrayList();
也就是在运行中跟String 没有半点联系。
但如果你是这样的
class MyArrayList extends ArrayList<String> {
}
那么在MyArrayList.class 中所有的泛型都会被替换为String .那么此时如果运行代码中出现
T t =(T)obj;
就是我们期望的结果了。
综上 ,这是我所碰到的问题,也是一个陷阱
public class TestOne<T> {
Listener<T> listener = null;
T str;
public void setListener(Listener<T> listener) {
this.listener = listener;
}
public void setValue(String v) {
str = (T) v;
}
public void run() {
listener.onChanged(str);
}
public static void main(String[] args) {
TestOne<String> test = new TestOne<String>();
test.setListener(new MyListener());
test.setValue("hello");
test.run();
}
}
class MyListener implements Listener<String> {
public void onChanged(String... addr) {
System.out.println("onChanged:" + addr);
}
}
interface Listener<T> {
void onChanged(T... addr);
}
TestOne是个公共类,其实现和具体的String类没有任何关联, 而其实例化过程被
TestOne<String> test = new TestOne<String>();
被蒙蔽了,在运行过程中,其内部的泛型全部替换为Object,那么在其对象中跑的数据也都是Object,所以传入到onChanged也为Object类型,这样发生Cast Exception在所难免,看class文件,在传递给onChanged函数前,会进行Object[] 强转。但是如果将数组更改为ArrayList就是ok的。:
public class TestTwo<T> {
ListenerTwo<T> listener = null;
T str;
public void setListener(ListenerTwo<T> listener) {
this.listener = listener;
}
public void setValue(String v) {
str = (T) v;
}
public void run() {
ArrayList<T> list = new ArrayList<T>();
list.add(str);
listener.onChanged(list);
}
public static void main(String[] args) {
TestTwo<String> test = new TestTwo<String>();
test.setListener(new MyListenerTwo());
test.setValue("hello");
test.run();
}
}
class MyListenerTwo implements ListenerTwo<String> {
public void onChanged(ArrayList<String> addr) {
System.out.println("onChanged:" + addr.get(0));
}
}
interface ListenerTwo<T> {
/**
* 如果使用... 就会出现[Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
*/
void onChanged(ArrayList<T> addr);
}
背景:
interface A<T> { //T是泛型
void method(T data) ;
}
class B implement A<D> {
void method(D data) {
...
}
}
调用:
class Caller {
E data; // E是D的抽象类,为什么不直接用D呢,因为Caller自身是个共用类,所以E选用的是抽象类,不跟具体业务类D挂钩。
B b;
void call(E data) {
b.method(data);//在调用这个的时候,出现cast异常。
}
}
问题:
这个和Integer及int的自动装箱完全没有关联,你将一个E对象赋给D对象,而中间没有经过强转,当然是有问题的。
如何解决:
方法一:反射
class Caller {
E data;
B b;
void call(E data) {
//通过反射获取得到b.method的参数类类型Class classOfD
//data经过类型强转 classOfD.cast(data)
b.method(data);
}
}
方法二:泛型
class Caller<T> {
T data;
B b;
void call(T data) {
b.method(data);
}
}
//实际调用时
Caller<D> caller = new Caller();