java Cast Exception
2016-04-11 19:40
405 查看
以下都是错误的。问题是我对运行时泛型擦除机制理解不够,太low。
这里给List设置String,能在编译阶段起到检查的功能,也就是如果如下,编译的时候会报错。
但是一旦通过编译到了运行阶段,泛型String会被擦除,就没有String 之分了,只有一个单纯的List。
更进一步说,什么能够在编译阶段检查出来呢?
就如同上面,代码调用含泛型参数的接口,传入一个参数,会对这个参数的类型进行检查。但是别指望运行期间给你做什么了。
但是对于工作代码,就要谨慎了。比如方法中有一句代码是这样的:
那么实际的情况,这就没有作用,类型强转发生在代码运行中的。在class文件的形式就是:
Object t = (Object) obj;
记住这种实例方式
到了Class那里就变成
也就是在运行中跟String 没有半点联系。
但如果你是这样的
那么在MyArrayList.class 中所有的泛型都会被替换为String .那么此时如果运行代码中出现
就是我们期望的结果了。
综上 ,这是我所碰到的问题,也是一个陷阱
TestOne是个公共类,其实现和具体的String类没有任何关联, 而其实例化过程被
被蒙蔽了,在运行过程中,其内部的泛型全部替换为Object,那么在其对象中跑的数据也都是Object,所以传入到onChanged也为Object类型,这样发生Cast Exception在所难免,看class文件,在传递给onChanged函数前,会进行Object[] 强转。但是如果将数组更改为ArrayList就是ok的。:
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();
总结:
相关文章推荐
- 初学SpringMVC(阅读了解)
- javacc学习总结
- 【Java学习-J.160411.0.7】笔记6-Java语言特点及数据类型
- Java第四周作业
- maven工程启动找不到Spring ContextLoaderListener的解决办法
- Java并发编程系列之二十九:正确终止与恢复线程(续)
- java instanceof与isAssignableFrom
- Spring中Quartz的配置
- Spring整个Ibatis之SqlMapClientDaoSupport
- Struts中数据回显,防止表单重复提交
- Java学习笔记(一)
- Java学习笔记(一)
- Struts 简单UI标签,ognl表达式语言几个符号
- MyBatis3与Spring3无缝集成-从iBatis平滑过渡
- Struts数据效验
- Java_chapter_15_图形
- 加密Spring加载的Properties文件
- 《JAVA源码分析》:LinkedList
- Spring实现数据库读写分离/spring事务配置解释(Annotation/Spring AOP/Reflection)
- Reserve java调用R语言