本站首页    管理页面    写新日志    退出


«December 2025»
123456
78910111213
14151617181920
21222324252627
28293031


公告
本博客在此声明所有文章均为转摘,只做资料收集使用。并无其他商业用途。

我的分类(专题)

日志更新

最新评论

留言板

链接

Blog信息
blog名称:
日志总数:210
评论数量:205
留言数量:-19
访问次数:931481
建立时间:2007年5月10日




[J2SE相关]JDK1.5新特性之generic-泛型/类属(2)
文章收藏,  网上资源,  软件技术,  电脑与网络

李小白 发表于 2007/6/6 22:42:09

这一篇是接着上文继续的,在这里补充说明,虽然我希望以双语写作,但是把英文文档翻译过来后再翻译回去,似乎是件好傻的事情。。。所以这些翻译并精简的文章算是个例外吧。 第一道虎纹: generic -泛型 / 类属(二) 泛型方法 假设我们想把一个数组的元素都放到一个容器类里,下面是第一次尝试: 500)this.width=500'>500)this.width=500" align=top border=0> 500)this.width=500'>500)this.width=500" align=top border=0> static   void  fromArrayToCollection(Object[] a, 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 o : a)  500)this.width=500'>500)this.width=500" border=0> {          c.add(o);  //  compile time error  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 > 来作为参数,你也许也发现了用 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> static   <  T  >   void  fromArrayToCollection(T[] a, Collection  <  T  >  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  (T o : a)  500)this.width=500'>500)this.width=500" border=0> {          c.add(o);  //  correct  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> 方法的声明加入了类型参数,在上面这个方法里,如果c 的元素类型是 a 的元素类型的父类,就能成功执行方法。下面这些代码可以帮助你了解一下: 500)this.width=500'>500)this.width=500" align=top border=0> Object[] oa  =   new  Object[ 100 ]; 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  >  co  =   new  ArrayList  <  Object  >  (); 500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0>fromArrayToCollection(oa, co);  //  T inferred to be Object  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[] sa  =   new  String[ 100 ]; 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  <  String  >  cs  =   new  ArrayList  <  String  >  (); 500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0>fromArrayToCollection(sa, cs);  //  T inferred to be String  500)this.width=500'>500)this.width=500" align=top border=0> 500)this.width=500'>500)this.width=500" align=top border=0>fromArrayToCollection(sa, co);  //  T inferred to be Object  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[] ia  =   new  Integer[ 100 ]; 500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0>Float[] fa  =   new  Float[ 100 ]; 500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0>Number[] na  =   new  Number[ 100 ]; 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  <  Number  >  cn  =   new  ArrayList  <  Number  >  (); 500)this.width=500'>500)this.width=500" align=top border=0>500)this.width=500'>500)this.width=500" align=top border=0>fromArrayToCollection(ia, cn);  //  T inferred to be Number  500)this.width=500'>500)this.width=500" align=top border=0> 500)this.width=500'>500)this.width=500" align=top border=0>fromArrayToCollection(fa, cn);  //  T inferred to be Number  500)this.width=500'>500)this.width=500" align=top border=0> 500)this.width=500'>500)this.width=500" align=top border=0>fromArrayToCollection(na, cn);  //  T inferred to be Number  500)this.width=500'>500)this.width=500" align=top border=0> 500)this.width=500'>500)this.width=500" align=top border=0>fromArrayToCollection(na, co);  //  T inferred to be Object  500)this.width=500'>500)this.width=500" align=top border=0> 500)this.width=500'>500)this.width=500" align=top border=0>fromArrayToCollection(na, cs);  //  compile-time error  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> 注意到我们并没有真正的传入一个类型实参,而是由编译器以方法的实际参数对象来推断,它推断出使得这次方法调用成立的类型,并尽可能地特化这个类型。比如说如果T 推断为 Number 依然成立的时候,就不会推断为 Object 。 现在看来,泛型方法和通配符有些共通的地方,使得类属有一定的灵活性。那么什么时候用泛型方法,什么时候用通配符?看看下面的例子: 500)this.width=500'>500)this.width=500" align=top border=0> interface Collection < 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>   public boolean containsAll(Collection < ? > c); 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 boolean addAll(Collection < ? extends E > c); 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> interface Collection < 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>   public < T > boolean containsAll(Collection < T > c); 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 < T extends E > boolean addAll(Collection < T > c); 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>} 500)this.width=500'>500)this.width=500" align=top border=0> 这两种方式都达成了同样的目的,使得方法有了多态性。然而注意到在每个方法的声明中,T 只出现了一次,这种情况下就应该用通配符,通配符的主要目的就是提供弹性的泛化,而多态方法则用于表达两个或多个参数间的依赖关系,你回过头去看多态方法的第一个例子,是不是这个情况?如果不存在依赖关系需要表达,就不应该用多态方法,因为从可读性上来说,通配符更清晰。   而且有趣的是,它们并非水火不容,反而可以精妙配合,如下: 500)this.width=500'>500)this.width=500" align=top border=0> class Collections 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>  public static < T > void copy(List < T > dest, List < ? extends T > src) 500)this.width=500'>500)this.width=500" border=0>{ 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>} 


阅读全文(1822) | 回复(0) | 编辑 | 精华
 



发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)



站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.037 second(s), page refreshed 144798704 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号