论坛首页 Java企业应用论坛

关于java泛型的疑惑,大家一起讨论一下

浏览 8345 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2013-10-26  

今天看了一下java的泛型,在网上找到一片文章:
java 泛型 深入
http://www.blogjava.net/fancydeepin/archive/2012/08/25/386241.html
文章作者fancydeepin。
fancydeepin在文中说,“运行期间泛型并不存在,它在编译完成之后就已经被擦除了。”,并都给出了例子。
但是我试验过后发现泛型并没有在编译完成之后就被擦除。
试验环境:CentOS6.2,Oracle JDK 1.7.0_40,JD-GUI0.3.5
下面是我的试验代码(根据fancydeepin的修改的):
Java代码

package forenroll;  
  
import java.util.ArrayList;  
import java.util.List;  
  
public class Test {  
  
    List<Integer> interview = new ArrayList<Integer>();  
    public void test(List<String> list){  
        List<String>    list1 = new ArrayList<String>();  
        List<Integer> list2 = new ArrayList<Integer>();  
        System.out.println(list1.getClass() == list2.getClass()); // 输出结果: true  
        System.out.println(list1.getClass() == interview.getClass()); // 输出结果: true  
        System.out.println(list1.getClass().getName()); // 输出结果: java.util.ArrayList  
        System.out.println(list2.getClass().getName()); // 输出结果: java.util.ArrayList  
    }  
    public static void main(String[] args) {  
  
        List<String>    list1 = new ArrayList<String>();  
        List<Integer> list2 = new ArrayList<Integer>();  
        Test test = new Test();   
        test.test(list1);  
  
    }  
  
}  

 
运行结果:
Java代码

true  
true  
java.util.ArrayList  
java.util.ArrayList 

  


JDK自带的javap命令反编译的结果:
Java代码

[forenroll@forenroll forenroll]$ javap Test  
Warning: Binary file Test contains forenroll.Test  
Compiled from "Test.java"  
public class forenroll.Test {  
  java.util.List<java.lang.Integer> interview;  
  public forenroll.Test();  
  public void test(java.util.List<java.lang.String>);  
  public static void main(java.lang.String[]);  
}  

 
main方法里面的两句代码不知道为什么没有反编译出来。但是我用jd-gui这个工具反编译出来的结果里面是有的,jd-gui反编译结果如下:
Java代码

package forenroll;  
  
import java.io.PrintStream;  
import java.util.ArrayList;  
import java.util.List;  
  
public class Test  
{  
  List<Integer> interview = new ArrayList();  
  
  public void test(List<String> list) { List list1 = new ArrayList();  
    List list2 = new ArrayList();  
    System.out.println(list1.getClass() == list2.getClass());  
    System.out.println(list1.getClass() == this.interview.getClass());  
    System.out.println(list1.getClass().getName());  
    System.out.println(list2.getClass().getName()); }  
  
  public static void main(String[] args)  
  {  
    List list1 = new ArrayList();  
    List list2 = new ArrayList();  
    Test test = new Test();  
    test.test(list1);  
  }  
}  

 
       根据通过javap命令和jd-gui工具之间的反编译结果,fancydeepin通过反编译的结果来说泛型在编译后被擦出了,我觉得这个说法不太妥。

       另外,javap和JD-GUI的反编译结果也不同(主要在方法体中的内容),这个反编译出来的泛型被擦除的原因是不是反编译器在反编译的过程中做了什么处理?因为fancydeepin与我的环境和JDK版本可能都不一样。

       但是那两个类型比较的结果又是ture,这个有点不理解了。不知有没有高手出来释疑解惑一下?

 

   发表时间:2013-10-29  
那个两个getClass 的=判断为空,和有没泛型的类型擦除有关系吗???
换句话说,你的这个例子,压根没在证明是否有擦除啊.

还有,为什么你的javap里能看到具体的类型,你可以自己搜索相关的内容,关键字是 LocalVariableTypeTable
0 请登录后投票
   发表时间:2013-10-29  
chenjingbo 写道
那个两个getClass 的=判断为空,和有没泛型的类型擦除有关系吗???
换句话说,你的这个例子,压根没在证明是否有擦除啊.

还有,为什么你的javap里能看到具体的类型,你可以自己搜索相关的内容,关键字是 LocalVariableTypeTable

多谢指点。我知道这个就是没有证明类型被擦处了。这个例子是我从别处看到的,有所质疑,怕我理解错了,所以将它拿过来请教的。
0 请登录后投票
   发表时间:2013-10-30  
楼主理解错了。
所谓的泛型类型擦除指的是在java代码运行阶段,泛型将失去检测集合内元素类型的能力,也就是这种强制约束能力只在编译阶段起作用。
但是在代码的运行阶段并不会擦除泛型的全部信息,比如在代码运行阶段依然可以通过反射来得到集合内元素的类型。
0 请登录后投票
   发表时间:2013-10-30  
cuidongdong1234 写道
楼主理解错了。
所谓的泛型类型擦除指的是在java代码运行阶段,泛型将失去检测集合内元素类型的能力,也就是这种强制约束能力只在编译阶段起作用。
但是在代码的运行阶段并不会擦除泛型的全部信息,比如在代码运行阶段依然可以通过反射来得到集合内元素的类型。

怎么获得?
0 请登录后投票
   发表时间:2013-10-31  
davepkxxx 写道
cuidongdong1234 写道
楼主理解错了。
所谓的泛型类型擦除指的是在java代码运行阶段,泛型将失去检测集合内元素类型的能力,也就是这种强制约束能力只在编译阶段起作用。
但是在代码的运行阶段并不会擦除泛型的全部信息,比如在代码运行阶段依然可以通过反射来得到集合内元素的类型。

怎么获得?


反射,具体api你查一下吧
0 请登录后投票
   发表时间:2013-10-31  
泛型是在编译期间进行检查的,在实际运行期间不会存在,你可以这样来试验下

先定义一个带泛型的List : List<Integer> list = new ArrayList<Integer>();
这个list已经添加泛型,存放integer数据类型,这时我们添加一个list.add("abc"); 编译器就会报错

但是你可以通过反射来往list中添加"abc" ,这就是运行期没有检查
0 请登录后投票
   发表时间:2013-10-31  
zhoujiangzi 写道
泛型是在编译期间进行检查的,在实际运行期间不会存在,你可以这样来试验下

先定义一个带泛型的List : List<Integer> list = new ArrayList<Integer>();
这个list已经添加泛型,存放integer数据类型,这时我们添加一个list.add("abc"); 编译器就会报错

但是你可以通过反射来往list中添加"abc" ,这就是运行期没有检查

受教了,多谢!
0 请登录后投票
   发表时间:2013-11-01   最后修改:2013-11-01
    public void test(List<String> list) {

    }

    public void test(List<Integer> list) {

    }


这样的例子才能说明是 Java 是使用了类型擦除的方式来实现的泛型,因为这样是错误的,使用了类型擦除导致两个重载的方法是完全一样的,所以是无法编译通过的,你打印getName在编译期间都搞定了,当然打印出来没问题了。
0 请登录后投票
   发表时间:2013-11-01  
fxl545826 写道
    public void test(List<String> list) {

    }

    public void test(List<Integer> list) {

    }


这样的例子才能说明是 Java 是使用了类型擦除的方式来实现的泛型,因为这样是错误的,使用了类型擦除导致两个重载的方法是完全一样的,所以是无法编译通过的,你打印getName在编译期间都搞定了,当然打印出来没问题了。

亲,无法编译通过,不代表运行期也无法运行哦..无法编译通过只能说无法不符合java语言规范.但是与jvm规范还是不一样的
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics