关于泛型的问题

oldhomelh 2011-03-29 10:53:27
这几天在看泛型,觉得越看越怪 首先 这个泛型变量在编译时候哦会被擦除 那么就会用其原始类型去替代,若是无限制类型的话 就用object 但是这样的话 实际应用中又怎么知道该变量 会是尖括号中份额类型参数的类型 ~~~~ 不知道编译器在这块做了什么
...全文
209 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
oldhomelh 2011-03-30
  • 打赏
  • 举报
回复
~~可能没说清楚吧~~ 就是java虚拟机对待泛型的话 比如class pair<T>{ T r;}
这个类 在编译时候虚拟机会把其T给擦除 类用一个原始类型代替即pair类型 而变量r 则变为Object类型的变量 (没有给予限定类型的话) 那么我在主方法中使用pair<String> a=new pair<String> 它又能识别出尖括号中的类型参数, 我想问的是 明明编译都成了object 到了主方法调用时候又是如何识别并转换为相应类型 我有点不理解 用了javap 查看字节码 也还是不很理解 我所看到的 全是object~~~类型
suntingtingonly 2011-03-30
  • 打赏
  • 举报
回复
链接不少。
skineffect 2011-03-30
  • 打赏
  • 举报
回复
ma_xupeng的回复很好,感觉关键还是得从编译器编译的字节码上去看。
qilimazhaluo 2011-03-30
  • 打赏
  • 举报
回复
这里有自动装箱啊,add 进去的还是一个 Integer
jaygo311 2011-03-30
  • 打赏
  • 举报
回复
List<Integer> ls = new ArrayList<Integer>();
ls.add(1);
Integer i = ls.get(0);


这就是一个很典型的泛型的例子,不知道楼主想要什么结果
xinmutou 2011-03-30
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 lxbccsu 的回复:]
楼上的ma_xupeng说清楚了。

其实楼主也明白泛型是编译器行为,而不是JVM行为;
并且也明白泛型是JDK5中引入的,以前的版本是没有泛型机制的;
那泛型擦除,用一个原始类型代替,如何识别并转换为相应类型?

那如果没有泛型,要进行类型转换,在以前的老版本中,楼主肯定会很容易的知道,是用强制类型转换来进行类型转换的,就是在要转换的类型前加个()和转换类型。既然JDK5中不需要强制……
[/Quote]

正解,编译器替你做了强制类型转换而已,也减少了你出错的几率,如类型转换错误
lxbccsu 2011-03-30
  • 打赏
  • 举报
回复
楼上的ma_xupeng说清楚了。

其实楼主也明白泛型是编译器行为,而不是JVM行为;
并且也明白泛型是JDK5中引入的,以前的版本是没有泛型机制的;
那泛型擦除,用一个原始类型代替,如何识别并转换为相应类型?

那如果没有泛型,要进行类型转换,在以前的老版本中,楼主肯定会很容易的知道,是用强制类型转换来进行类型转换的,就是在要转换的类型前加个()和转换类型。既然JDK5中不需要强制类型转换,那总要有个地方来转换,因为JVM是和以前的行为一致的,这就明白了,是编译器做了处理,以前程序中强制类型转换的代码现在由编译器来生成,这样我们写的代码即美观又方便,还减少了错误(如果仅仅是为了美观、方便,那不能说是个显著的特性了),提高了类型转换安全性。

编译器怎样编译泛型表达式和泛型方法:
编译泛型表达式,如果返回类型擦除,编译器会插入强制类型转换。
而泛型方法类型擦除有时会很复杂,像多态中,常会合成桥方法来保持多态。
楼主可以再看看相关书籍详细了解,看编译器会怎样处理。
最好的是用个老版本的编译器生成class,然后用JDK5或之后的版本生成一份class,对照一下。

其实保证了程序的正确性,编译器还可以优化代码。
老马睡不醒 2011-03-30
  • 打赏
  • 举报
回复
代码:

List<Integer> ls = new ArrayList<Integer>();
ls.add(1);
Integer i = ls.get(0);

javap -c 结果

0: new #2; //class java/util/ArrayList
3: dup
4: invokespecial #3; //Method java/util/ArrayList."<init>":()V
7: astore_1
8: aload_1
9: iconst_1
10: invokestatic #4; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
13: invokeinterface #5, 2; //InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
18: pop
19: aload_1
20: iconst_0
21: invokeinterface #6, 2; //InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
26: checkcast #7; //class java/lang/Integer
29: astore_2

注意第10行和第26行的类型转换。
老马睡不醒 2011-03-30
  • 打赏
  • 举报
回复
JAVA编译器生成代码时会自动加入类型转换或类型检查,如:

List<Integer>擦除后变成List,
当我们执行get()时,编译器会在返回语句上自动加入(Integer)x的操作,将Object转为Integer类型
同理,当执行add()时,编译器会在方法的一开始添加检查参数是否为Integer的操作,如果不是,则抛出异常。
建议看下Thinking in Java,里面有很详细的解释。
Ganymede 2011-03-30
  • 打赏
  • 举报
回复
楼主说的没错,Thinking in java里也有相关的证明,擦除确实将方法或类内部的实际信息去除掉。但是编译器会留个记号,也就是边界处理。在对象进入并且离开方法的时候做个记号,进行二次编译,也就是说一旦进入该方法,编译器会进行类型检查,然后离开方法的时候会对值进行强制类型转换。
Ganymede 2011-03-29
  • 打赏
  • 举报
回复
如果是Object的话 实际中会强制转换为你需要的类型
聆听随风 2011-03-29
  • 打赏
  • 举报
回复
执行的版本号?

62,623

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧