博客已转到HuJinPu 's blog

http://blog.csdn.net/hujinpu

首页 新随笔 联系 聚合 管理
  24 Posts :: 0 Stories :: 25 Comments :: 0 Trackbacks

大家先看看下面这段小程序

import  java.util.ArrayList;
import  java.util.List;

// 申明一个泛型类
public   class  GenericClass  {
    
    
public   static   void  main(String [] args)  {
        List
< Integer >  list  =   new  ArrayList < Integer > ();
        list.add(
1 );
        list.add(
2 );
        
new  Product().prt(list);
    }

}


// 制造一个类用于说明问题
class  Product   {
    
public   void  prt(List < String >  lt)  {
        System.out.println(lt);
    }

}


 

编译器报错,说无法将Product中的prt(java.util.List<java.lang.String>)应用于(java.util.List<java.lang.Integer>)。前面定义了List<Integer> list = new ArrayList<Integer>();后面却调用 public void prt(List<String> lt)用list做参数,肯定是错误的用法。编译器报错的行为是很正确的,他帮助你避免了潜在错误的发生。这里要注意泛型的作用:List<Integer>和List<String>虽然看着都是List,但编译器把他们当作不同的class,不能相互替代。这是泛型的基本原则。你可以把他们看成一个是Class1, 一个是Class2, 当然不能给一个需要类型为Class1的参数的方法传一个类型为Class2的参数的方法啦。

再来看上面程序稍微改动一处的情况

import  java.util.ArrayList;
import  java.util.List;

// 申明一个泛型类
public   class  GenericClass  {
    
    
public   static   void  main(String [] args)  {
        List
< Integer >  list  =   new  ArrayList < Integer > ();
        list.add(
1 );
        list.add(
2 );
        
new  Product().prt(list);
    }

}


// 制造一个类用于说明问题
class  Product < T >   {
    
public   void  prt(List < String >  lt)  {
        System.out.println(lt);
    }

}


编译器说使用了未经检查或不安全的操作,但能编译通过并运行显示 [1, 2]。

这又是为什么呢?就是红色的那一个<T>就变化这么大吗?似乎不是和刚才效果应该一样拉,怎么这回又可以了?

原因是这样的:第次程序里面,只是把class Product改成了class Product<T>,尽管类型T在Product的代码里压根从没用到,但是这个定义把一个普通类(class)变成了原始类型(raw class)。generic class Product<T>在JVM运行时是不存在的,Product这个原始类型不是类型安全的。因为在new Product.prt(list)里面,使用的是原始类型的Product,所以里面的list也会被擦拭成原始类型的,所以类型就符合了,不会有编译错误而可以运行。

虽然这个时候程序尽管可以运行,但其使用泛型的方法,无疑是错误的。 在这里我只是想和大家分析一些泛型的细节问题。要大家通过这个细节明白泛型的细节之处(檫试,原始类型)。具体的内容我就不在说了,很多书都有。推荐java参考大全5edition page264 和 core Java I 7edition Chapter 13. Generic Programming  

posted on 2006-08-28 16:19 livahu 阅读(1546) 评论(5)  编辑  收藏 所属分类: Java

Feedback

# re: 关于jdk1.5泛型的思考 2006-08-28 17:17 海蓝
@livahu
你在原因部分说的内容我看不懂啊,感觉你说的原因和结果之间似乎没什么必然的联系,可以再整理一下吗?  回复  更多评论
  

# re: 关于jdk1.5泛型的思考 2006-08-28 18:29 路人甲
这个问题我想的确是作者没有说清楚。不过只要亲自用编译器试一下应该就可以很容易理解了。这里斗胆帮作者稍微深入地解释一下,如果说错了还请不吝赐教,但愿不会误人子弟。

首先,第一段程序里面,前面定义了List<Integer> list = new ArrayList<Integer>();
后面却调用void prt(List<String> l)用list做参数,肯定是错误的用法。编译器报错的行为是很正确的,他帮助你避免了潜在错误的发生。

这里要注意泛型的作用。List<Integer>和List<String>虽然看着都是List,但编译器把他们当作不同的class,不能相互替代。这是泛型的基本原则。你可以把他们看成一个是Class1, 一个是Class2, 当然不能给一个需要类型为Class1的参数的方法传一个类型为Class2的参数的方法啦。

而第二段程序里面,只是把class Product改成了class Product <T>,尽管类型T在Product的代码里压根从没用到,只是这个定义把一个普通类(class)变成了原始类型(raw class)。其实可以自己试一下,一旦把Fangxin.main()里面的new Product().prt(list) 改成了new Product<Integer>().prt(list), (这里面的Integer可以换成任何一个合法的类),那么warning没有了,原来的error又回来了。

也就是说,一旦把Product定义成了原始类型,那么在使用这个class的时候也就应该使用Product<T>的形式,否则的话,编译器会认为你的行为不正常或是很危险,所以给你一个warning(也许你只是忘了写呢)。正像作者原文里写道的:

generic class Product<T>在JVM运行时是不存在的,Product叫原始类型,原始类型不是类型安全的.这个在编译时是检测不出的,运行时才报错.
(这里其实不会报错,只是因为可能会报错,所以编译器给你一个warning)。

而当一个generic class使用原始类型时,其方法里的参数也就相应的使用了原始形态,如此列的java.util.List而不是java.util.List<String>
固new Product().prt(lt)时可以运行.

(这句是说,因为在new Product.prt(list)里面,你使用的是原始类型的Product,所以里面的list也是原始类型的,所以类型就符合了,不会有编译错误而可以运行)。

但是这个时候尽管可以运行,但程序的逻辑,至少其使用泛型的方法,无疑是错误的。

个人认为这个程序应该改成这样才是正确地使用泛型编程的方式:

import java.util.ArrayList;
import java.util.List;

public class Fangxin {

public static void main(String [] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
new Product<Integer>().prt(list);
}

}

class Product<T> {
public void prt(List<T> l) {
System.out.println(l);
}
}

最后加一句,编译器给出error和warning不是故意跟你作对,给你添麻烦,而是为你写出正确的程序提出最好的帮助。所以应该尽量让程序没有任何编译错误(这个自然)和警告才是正途。  回复  更多评论
  

# re: 关于jdk1.5泛型的思考 2006-08-28 20:52 livahu
很感谢路人甲的指正,我确实没有表达清楚我的想法,我想通过路人甲的指正,大家应该明白了泛型的细节之处,这里的带有明显错误和警告的程序不是要大家去模仿,而是要大家通过这个细节明白泛型的细节之处(檫试,原始类型).具体的内容我就不在说了,很多书都有,推荐java参考大全5edition page264 和 core Java I 7edition Chapter 13. Generic Programming  回复  更多评论
  

# re: 关于jdk1.5泛型的思考 2006-08-29 09:00 Dedian
good article, just for supplement:

http://www.blogjava.net/dedian/archive/2006/06/23/54615.html  回复  更多评论
  

# re: 关于jdk1.5泛型的思考 2006-09-01 10:16 Spike Wang
这样的用法1.5以后才有,最好不要乱用泛型。

我建议如果是新项目使用无所谓。

如果是和以前系统协作那么最好避免。

免得给自己找麻烦。

在泛型还么大量使用的时候,尽量避免使用。

  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: