« | September 2025 | » | 日 | 一 | 二 | 三 | 四 | 五 | 六 | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | | | | | |
| 公告 |
本博客在此声明所有文章均为转摘,只做资料收集使用。并无其他商业用途。 |
Blog信息 |
blog名称: 日志总数:210 评论数量:205 留言数量:-19 访问次数:920229 建立时间:2007年5月10日 |

| |
[J2SE相关]JDK1.5新特性之generic-泛型/类属 文章收藏, 网上资源, 软件技术, 电脑与网络
李小白 发表于 2007/6/6 22:40:18 |
在学习 java 1.5 的过程中,我使用了 sun 公布的 tutorial ,这份文档写的比较详尽易明,但是对于想快速了解 tiger 而且具有较好 java 基础的人来说,大篇幅的英文文档是比较耗时间和非必需的,所以我将会归纳这份文档的主要内容,在保证理解的底线上,尽力减少阅读者需要的时间。
在以下地址可以进入各新增语言特色介绍以及下载相关文档(若有)。
http://java.sun.com/j2se/1.5.0/docs/relnotes/features.html
第一道虎纹: generic -泛型 / 类属
什么是泛型
泛型让你在类这一层次上进行抽象。看看例子:
500)this.width=500'>500)this.width=500" align=top border=0> List myIntList = new LinkedList(); // 1 500)this.width=500'>500)this.width=500" align=top border=0> 500)this.width=500'>500)this.width=500" align=top border=0>myIntList.add( new Integer( 0 )); // 2 500)this.width=500'>500)this.width=500" align=top border=0> 500)this.width=500'>500)this.width=500" align=top border=0>Integer x = (Integer) myIntList.iterator().next(); // 3 500)this.width=500'>500)this.width=500" align=top border=0>
第 3 句的转换类型有点麻烦吧~?编译器只能保证容器类里放的是 Object 对象,要使用他们只能这样去转换。而且这样的转换也并不是完全安全的,程序员可能犯错误,容器里的对象未必是他以为的对象。有没有办法显式地表达出程序员的意图,将该容器限制为只能保存特定类型的对象?这正是 generic -泛型的核心用意。
500)this.width=500'>500)this.width=500" align=top border=0> List < Integer > myIntList = new LinkedList < Integer > (); // 1’ 500)this.width=500'>500)this.width=500" align=top border=0> 500)this.width=500'>500)this.width=500" align=top border=0>myIntList.add( new Integer( 0 )); // 2’ 500)this.width=500'>500)this.width=500" align=top border=0> 500)this.width=500'>500)this.width=500" align=top border=0>Integer x = myIntList.iterator().next(); // 3’ 500)this.width=500'>500)this.width=500" align=top border=0>
这样子我们就声明了一个只放 Integer 的 List ,我们说 List 是一个 generic Interface ,接收了一个类型参数,在上例中就是 Integer 。在初始化的时候,同样的也指定了这个类型参数。
要注意这些工作的效果不是仅仅把原来的第 3 句的转换工作省掉,而是由此让编译器确保了这个 List 在程序的任何位置任何时候都用以存放正确的类型,而原来的类型转换仅仅告诉我们在这一单点处程序员自己认为的类型。
泛型由此为程序,尤其是大型程序,带来了可读性和健壮性。
定义简单的泛型
500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0>public interface List < E > 500)this.width=500'>500)this.width=500" border=0>{ 500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0> void add(E x); 500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0> Iterator < E > iterator(); 500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0>} public interface Iterator < E > 500)this.width=500'>500)this.width=500" border=0>{ 500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0> E next(); 500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0> boolean hasNext(); 500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0>} 500)this.width=500'>500)this.width=500" align=top border=0>
尖括号内的标识符就是一个类型形式参数。类似于方法的参数,当你使用的时候就替换一个实际参数进去,只不过这个参数是个类型。在上面的例子中,我们就替换了一个Integer 类型进去。
在这里稍微说一下命名的规范,定义泛型中的形式参数时,使用简洁有力又具有启发性的名字,如果可以的话用单个字母更好。避免使用小写,以免和普通的方法参数混淆。
泛型与子类
看看以下的例子语句合法吗?
500)this.width=500'>500)this.width=500" align=top border=0> List < String > ls = new ArrayList < String > (); // 1 500)this.width=500'>500)this.width=500" align=top border=0> 500)this.width=500'>500)this.width=500" align=top border=0>List < Object > lo = ls; // 2 500)this.width=500'>500)this.width=500" align=top border=0>
第 2 句是行不通的,看看以下的语句:
500)this.width=500'>500)this.width=500" align=top border=0> lo.add( new Object()); // 3 500)this.width=500'>500)this.width=500" align=top border=0> 500)this.width=500'>500)this.width=500" align=top border=0>String s = ls.get( 0 ); // 4: 试图将 Object 对象赋值给字符串对象,编译错误 500)this.width=500'>500)this.width=500" align=top border=0>
简而言之就是,原有类型的继承关系是不会反映到对应的泛型上来,在上述情况下,任何两个泛型类型都不存在继承关系。那么,习惯了面向接口编程的我们怎样去适应这种严格的使用限制呢?
通配符
假如我们要用一个方法把一个容器内的元素都 print 出来,可以用这样的代码来实现 :
500)this.width=500'>500)this.width=500" align=top border=0> 500)this.width=500'>500)this.width=500" align=top border=0> void printCollection(Collection c) 500)this.width=500'>500)this.width=500" border=0> { 500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0> Iterator i = c.iterator(); 500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0> for (k = 0; k < c.size(); k++) 500)this.width=500'>500)this.width=500" border=0>{ 500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0> System.out.println(i.next()); 500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0> } } 500)this.width=500'>500)this.width=500" align=top border=0>
如果我们用新的泛型和新的for 语句(你可以先不了解它,以后会谈到)来尝试同样的功能,以下代码可行吗?
500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0>void printCollection(Collection < Object > c) 500)this.width=500'>500)this.width=500" border=0>{ 500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0> for (Object e : c) 500)this.width=500'>500)this.width=500" border=0>{ 500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0> System.out.println(e); 500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0> }500)this.width=500'>500)this.width=500" align=top border=0>}500)this.width=500'>500)this.width=500" align=top border=0>
事实是,新的代码的使用范围非常有限,因为 Collection < Object > 就只是一个放 Object 的容器泛类,它不是 任何其他 Collection 泛类的父类!真正担任这个角色的是:
Collection < ? >
这个问号代表了未知, Collection < ? > 的元素可以是任何类型,这就是通配类型。
现在我们可以这样写:
500)this.width=500'>500)this.width=500" align=top border=0> 500)this.width=500'>500)this.width=500" align=top border=0> void printCollection(Collection < ? > c) 500)this.width=500'>500)this.width=500" border=0> { 500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0> for (Object e : c) 500)this.width=500'>500)this.width=500" border=0> { 500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0> System.out.println(e); 500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0> } } 500)this.width=500'>500)this.width=500" align=top border=0>
注意在循环里面,可以把元素赋值给一个 Object 类型,因为无论 c 里放的是什么,它肯定是一个 Object ,但向 c 里放置对象则是不安全的,因为不知道 c |
|
|