关于泛型的问题 这几天在看泛型,觉得越看越怪 首先 这个泛型变量在编译时候哦会被擦除 那么就会用其原始类型去替代,若是无限制类型的话 就用object 但是这样的话 实际应用中又怎么知道该变量 会是尖括号中份额类型参数的类型 ~~~~ 不知道编译器在这块做了什么 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 如果是Object的话 实际中会强制转换为你需要的类型 ~~可能没说清楚吧~~ 就是java虚拟机对待泛型的话 比如class pair<T>{ T r;}这个类 在编译时候虚拟机会把其T给擦除 类用一个原始类型代替即pair类型 而变量r 则变为Object类型的变量 (没有给予限定类型的话) 那么我在主方法中使用pair<String> a=new pair<String> 它又能识别出尖括号中的类型参数, 我想问的是 明明编译都成了object 到了主方法调用时候又是如何识别并转换为相应类型 我有点不理解 用了javap 查看字节码 也还是不很理解 我所看到的 全是object~~~类型 楼主说的没错,Thinking in java里也有相关的证明,擦除确实将方法或类内部的实际信息去除掉。但是编译器会留个记号,也就是边界处理。在对象进入并且离开方法的时候做个记号,进行二次编译,也就是说一旦进入该方法,编译器会进行类型检查,然后离开方法的时候会对值进行强制类型转换。 JAVA编译器生成代码时会自动加入类型转换或类型检查,如:List<Integer>擦除后变成List,当我们执行get()时,编译器会在返回语句上自动加入(Integer)x的操作,将Object转为Integer类型同理,当执行add()时,编译器会在方法的一开始添加检查参数是否为Integer的操作,如果不是,则抛出异常。建议看下Thinking in Java,里面有很详细的解释。 代码: 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行的类型转换。 楼上的ma_xupeng说清楚了。其实楼主也明白泛型是编译器行为,而不是JVM行为;并且也明白泛型是JDK5中引入的,以前的版本是没有泛型机制的;那泛型擦除,用一个原始类型代替,如何识别并转换为相应类型?那如果没有泛型,要进行类型转换,在以前的老版本中,楼主肯定会很容易的知道,是用强制类型转换来进行类型转换的,就是在要转换的类型前加个()和转换类型。既然JDK5中不需要强制类型转换,那总要有个地方来转换,因为JVM是和以前的行为一致的,这就明白了,是编译器做了处理,以前程序中强制类型转换的代码现在由编译器来生成,这样我们写的代码即美观又方便,还减少了错误(如果仅仅是为了美观、方便,那不能说是个显著的特性了),提高了类型转换安全性。编译器怎样编译泛型表达式和泛型方法:编译泛型表达式,如果返回类型擦除,编译器会插入强制类型转换。而泛型方法类型擦除有时会很复杂,像多态中,常会合成桥方法来保持多态。楼主可以再看看相关书籍详细了解,看编译器会怎样处理。最好的是用个老版本的编译器生成class,然后用JDK5或之后的版本生成一份class,对照一下。其实保证了程序的正确性,编译器还可以优化代码。 List<Integer> ls = new ArrayList<Integer>(); ls.add(1); Integer i = ls.get(0);这就是一个很典型的泛型的例子,不知道楼主想要什么结果 这里有自动装箱啊,add 进去的还是一个 Integer ma_xupeng的回复很好,感觉关键还是得从编译器编译的字节码上去看。 一道java编程题求高手指点啊! java对象中的属性判断空的问题 如何遍历ArrayList比较好 遇到一个关于类加载的问题 关于用Runtime.getRuntime().exec(cmd)调用子进程的生命周期问题 急救! 一个JSP出错问题,在线等 JBuilder9 enterprise enition download here ! come in! 向大家请教一个问题!!!急、急 各位兄弟姐妹谈谈关于JAVA连接数据库的方法怎么样??????来up也欢迎 请教一个正则表达式 jxl poi可不可以对一个有数据的Excel进行读写操作
这个类 在编译时候虚拟机会把其T给擦除 类用一个原始类型代替即pair类型 而变量r 则变为Object类型的变量 (没有给予限定类型的话) 那么我在主方法中使用pair<String> a=new pair<String> 它又能识别出尖括号中的类型参数, 我想问的是 明明编译都成了object 到了主方法调用时候又是如何识别并转换为相应类型 我有点不理解 用了javap 查看字节码 也还是不很理解 我所看到的 全是object~~~类型
当我们执行get()时,编译器会在返回语句上自动加入(Integer)x的操作,将Object转为Integer类型
同理,当执行add()时,编译器会在方法的一开始添加检查参数是否为Integer的操作,如果不是,则抛出异常。
建议看下Thinking in Java,里面有很详细的解释。
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行的类型转换。
并且也明白泛型是JDK5中引入的,以前的版本是没有泛型机制的;
那泛型擦除,用一个原始类型代替,如何识别并转换为相应类型?那如果没有泛型,要进行类型转换,在以前的老版本中,楼主肯定会很容易的知道,是用强制类型转换来进行类型转换的,就是在要转换的类型前加个()和转换类型。既然JDK5中不需要强制类型转换,那总要有个地方来转换,因为JVM是和以前的行为一致的,这就明白了,是编译器做了处理,以前程序中强制类型转换的代码现在由编译器来生成,这样我们写的代码即美观又方便,还减少了错误(如果仅仅是为了美观、方便,那不能说是个显著的特性了),提高了类型转换安全性。编译器怎样编译泛型表达式和泛型方法:
编译泛型表达式,如果返回类型擦除,编译器会插入强制类型转换。
而泛型方法类型擦除有时会很复杂,像多态中,常会合成桥方法来保持多态。
楼主可以再看看相关书籍详细了解,看编译器会怎样处理。
最好的是用个老版本的编译器生成class,然后用JDK5或之后的版本生成一份class,对照一下。其实保证了程序的正确性,编译器还可以优化代码。
ls.add(1);
Integer i = ls.get(0);
这就是一个很典型的泛型的例子,不知道楼主想要什么结果