锁定老帖子 主题:泛型理解上的一个问题
该帖已经被评为隐藏帖
|
|
---|---|
作者 | 正文 |
发表时间:2010-11-08
(1)对于arr1
就相当于Object o = arr1.get(0); (2)对于arr2 就相当于String obj2 = arr2.get(0);(报错) |
|
返回顶楼 | |
发表时间:2010-11-08
最后修改:2010-11-08
原来是System.out.println();造成的,以后遇到问题,一步步调试很是很必要的
再说,ArrayList里存放数据用的Object数组不是T数组。。 |
|
返回顶楼 | |
发表时间:2010-11-08
// Decompiled by DJ v3.6.6.79 Copyright 2004 Atanas Neshkov Date: 2010-11-08 9:27:39 // Home Page : http://members.fortunecity.com/neshkov/dj.html - Check often for new version! // Decompiler options: packimports(3) // Source File Name: Test.java package com.paic; import java.io.PrintStream; import java.lang.reflect.Method; import java.util.ArrayList; public class Test { public Test() { } public static void main(String args[]) throws Exception { ArrayList arr1 = new ArrayList(); ArrayList arr2 = new ArrayList(); System.out.println(arr1.getClass() == arr2.getClass()); arr1.add(Integer.valueOf(55)); arr1.getClass().getMethod("add", new Class[] { java/lang/Object }).invoke(arr1, new Object[] { "dodo" }); System.out.println(arr1.get(1)); arr2.add("why"); arr2.getClass().getMethod("add", new Class[] { java/lang/Object }).invoke(arr2, new Object[] { Integer.valueOf(33) }); System.out.println((String)arr2.get(1)); //看这一行 } } 这怎么能是System.out.println()的错误呢? 之前朋友给的反编译的代码我觉得就可以完全解释了。 编译后的代码是: System.out.println((String)arr2.get(1)); //看这一行 这句话Run的时候肯定就ClassCastException了。 虽然你在源码里面是写 arr2.get(1), 但是因为泛型的关系,编译后的代码给做了强制类型转换了。。。 |
|
返回顶楼 | |
发表时间:2010-11-08
最后修改:2010-11-08
悲剧了 写道 请帮忙解释下这个泛型问题,具体逻辑我都下在代码注释里面了
public class Test01 { public static void main(String[] args) throws Exception{ ArrayList<Integer> arr1=new ArrayList<Integer>(); ArrayList<String> arr2=new ArrayList<String>(); //下面打印出来true,证明泛型只是编译器级别的一个东西,加载到内存还是一样的 System.out.println(arr1.getClass()==arr2.getClass()); //那么可以用跳过编译器用反射直接加入不通类型的东西,测试打印出"dodo"字符串 arr1.add(55); arr1.getClass().getMethod("add", Object.class).invoke(arr1, "dodo"); System.out.println(arr1.get(1)); //既然如此那么下面这个也应该能正确打印,但是报异常异常为: java.lang.ClassCastException arr2.add("why"); arr2.getClass().getMethod("add", Object.class).invoke(arr2, 33); System.out.println(arr2.get(1)); } } 给你个终结贴吧: 请查看如下我修改的代码: public class Test01 { public static void main(String[] args) throws Exception{ ArrayList<Integer> arr1=new ArrayList<Integer>(); ArrayList<String> arr2=new ArrayList<String>(); //下面打印出来true,证明泛型只是编译器级别的一个东西,加载到内存还是一样的 System.out.println(arr1.getClass()==arr2.getClass()); //那么可以用跳过编译器用反射直接加入不通类型的东西,测试打印出"dodo"字符串 arr1.add(55); arr1.getClass().getMethod("add", Object.class).invoke(arr1, "dodo"); System.out.println(arr1.get(1)); //既然如此那么下面这个也应该能正确打印,但是报异常异常为: java.lang.ClassCastException arr2.add("why"); arr2.getClass().getMethod("add", Object.class).invoke(arr2, 33); // System.out.println(arr2.get(1));//这里其实和add的道理一样,还是没有绕过编译时泛型的检查 //如果你add的时候用反射绕过了,get的时候为什么不绕呢?? //arr1之所以可以是因为编译器自动将Integer看作Object自动调用了println(Object obj)方法,其实还是没有 //绕过编译时的泛型定义,只是有对应的println方法罢了,还是检查了<Integer>了的。pringln的时候会 //直接调用println(Object obj) //arr2同样会检查泛型类型,一看是<String>,那么就会找println(String s)方法,因为存在这个方法,所以 //直接调用了println(String s)该方法,这就是为什么arr2的out.pringln会调用打印String的方法,而不是 //打印Object的方法了,而调用String的pringln的方法必然会作(String)强转了。 //下面是get的时候也通过反射来绕过编译时泛型检查,肯定是没问题的。 //呵呵,没有任何矛盾,不明白请跟帖,我回回复。 Object obj1=arr2.getClass().getMethod("get", int.class).invoke(arr2, 1); System.out.println(obj1); } } //呵呵,没有任何矛盾,不明白请跟帖,我回回复。 |
|
返回顶楼 | |
发表时间:2010-11-08
只能说你们的回答太肤浅了。
ArrayList<Integer> arr1 =new ArrayList<Integer>(); arr1.add(11); System.out.println(arr1.getClass()); 多说无益,自己看看这个之后就知道是怎么回事了。 望大虾们,回贴时注意份量,不要影响我们这些菜鸟。谢谢 |
|
返回顶楼 | |
发表时间:2010-11-08
coffeesweet 写道 悲剧了 写道 请帮忙解释下这个泛型问题,具体逻辑我都下在代码注释里面了
public class Test01 { public static void main(String[] args) throws Exception{ ArrayList<Integer> arr1=new ArrayList<Integer>(); ArrayList<String> arr2=new ArrayList<String>(); //下面打印出来true,证明泛型只是编译器级别的一个东西,加载到内存还是一样的 System.out.println(arr1.getClass()==arr2.getClass()); //那么可以用跳过编译器用反射直接加入不通类型的东西,测试打印出"dodo"字符串 arr1.add(55); arr1.getClass().getMethod("add", Object.class).invoke(arr1, "dodo"); System.out.println(arr1.get(1)); //既然如此那么下面这个也应该能正确打印,但是报异常异常为: java.lang.ClassCastException arr2.add("why"); arr2.getClass().getMethod("add", Object.class).invoke(arr2, 33); System.out.println(arr2.get(1)); } } 给你个终结贴吧: 请查看如下我修改的代码: public class Test01 { public static void main(String[] args) throws Exception{ ArrayList<Integer> arr1=new ArrayList<Integer>(); ArrayList<String> arr2=new ArrayList<String>(); //下面打印出来true,证明泛型只是编译器级别的一个东西,加载到内存还是一样的 System.out.println(arr1.getClass()==arr2.getClass()); //那么可以用跳过编译器用反射直接加入不通类型的东西,测试打印出"dodo"字符串 arr1.add(55); arr1.getClass().getMethod("add", Object.class).invoke(arr1, "dodo"); System.out.println(arr1.get(1)); //既然如此那么下面这个也应该能正确打印,但是报异常异常为: java.lang.ClassCastException arr2.add("why"); arr2.getClass().getMethod("add", Object.class).invoke(arr2, 33); // System.out.println(arr2.get(1));//这里其实和add的道理一样,还是没有绕过编译时泛型的检查 //如果你add的时候用反射绕过了,get的时候为什么不绕呢?? //arr1之所以可以是因为编译器自动将Integer看作Object自动调用了println(Object obj)方法,其实还是没有 //绕过编译时的泛型定义,只是有对应的println方法罢了,还是检查了<Integer>了的。pringln的时候会 //直接调用println(Object obj) //arr2同样会检查泛型类型,一看是<String>,那么就会找println(String s)方法,因为存在这个方法,所以 //直接调用了println(String s)该方法,这就是为什么arr2的out.pringln会调用打印String的方法,而不是 //打印Object的方法了,而调用String的pringln的方法必然会作(String)强转了。 //下面是get的时候也通过反射来绕过编译时泛型检查,肯定是没问题的。 //呵呵,没有任何矛盾,不明白请跟帖,我回回复。 Object obj1=arr2.getClass().getMethod("get", int.class).invoke(arr2, 1); System.out.println(obj1); } } //呵呵,没有任何矛盾,不明白请跟帖,我回回复。 谢谢,分析得很好很清晰! |
|
返回顶楼 | |
发表时间:2010-11-08
麻烦大家去看一看。
ArrayList<String> arr1 = new ArrayList<String>(); ArrayList<Integer> arr2 = new ArrayList<Integer>(); System.out.println(arr1.getClass()); System.out.println(arr2.getClass()); 返回的是什么? 这个问题,我想不用我多说了。 |
|
返回顶楼 | |
发表时间:2010-11-08
擦除。。。。
|
|
返回顶楼 | |
发表时间:2010-11-09
yunzhiyifeng 写道 这应该是一个println重载的问题,并不是反射引起的classcastexception,
System.out.println(arr1.get(1)); //此时调用的是println(Object x)的方法,看代码: public void println(Object x) { String s = String.valueOf(x); synchronized (this) { print(s); newLine(); },这里会显示的调用valueOf()方法,所以在print的时候,都会调用该对象自身的toString,不会出异常。而System.out.println(arr2.get(1));此时arr2.get(1)的编译类型是String,所以调用的是println(String x),此时就不会做toString的操作,直接作为了String对象,所以编译器会产生checkcast语句,看arr2.get(1)能否转换为String,而此时arr2.get(1)是Integer,做类型转换的时候便会报错。 +1 范型是在编译的时候确定的,所以调用的是println(String x)方法,抛出classcastexception |
|
返回顶楼 | |