java 范型编程

1.一个简单的范型示例

在以前,你可能遇到过这样的代码:

1 List list  =   new  LinkedList(); 
2
3 list.add( " a " ); 
4
5 list.add( " b " ); 
6
7 list.add( " c " ); 
8
9 String name  =  (String)list.iterator.next(); 

注意,第三行需要强制转换。而使用范型:
 1
 2 List < String >  list  =   new  LinkedList < String > (); 
 3
 4 list.add( " a "
 5
 6 list.add( " b " ); 
 7
 8 list.add( " c " ); 
 9
10 String name  =  list.iterator.next(); 
11
12

这里将list声明成String类型的List。List是有一个类型参数的范型接口。这个例子中类型参数是String。

 
2.定义简单的范型

看j2se5.0中List和Iterator接口的实现(片断):
 1
 2 public   interface  List < E >   
 3
 4 {  
 5
 6 void  add(E x); 
 7
 8 Iterator < E >  iterator(); 
 9
10 }
 
11
12 public   interface  Iterator < E >   
13
14 {  
15
16 E next(); 
17
18 boolean  hasNext(); 
19
20 }
  
21
22

上面的代码我们比较熟悉,但是其中增加了尖括号。尖括号中的内容定义了接口List和Iterator的形式类型参数。类型参数可以用在范型声明中,如类和接口的声明。

一旦声明了范型,你就可以使用它。在上面的例子中使用了List<String>。这里使用String是实参,代替了形参E。如果使用List<Integer>,则用实参Integer代替了形参E。

不管List<Integer>还是List<String>,它们的类只有一个。考虑下面的代码:
1
2 List < String >  list1  =   new  LinkedList < String > (); 
3
4 List < Integer >  list2  =   new  LinkedList < Integer > (); 
5
6 System.out.println(list1.getClass() == list2.getClass()); 
7
 

输出结果为true。

 

一般来说,形式类型参数都是大写,尽量使用单个字母,许多容器类都使用E作为参数。

 

3.范型和继承

考虑下面的代码,你认为它会出错吗?

1
2 String s = " xxx@gmail.com "
3
4 Object o  =  s: 
5

当然,String类继承Object类,这样做不会出错。但下面的代码呢?

1 List < String >  s  =   new  LinkedList < String > (); 
2
3 List < Object > o = s; 
4


编译出错!

是的,List<Object>和List<String>没有继承关系。

 

4.通配符

考虑下面一个方法:

 1
 2 public   void  printCollection(Collection < Object >  c) 
 3
 4
 5
 6     for (Object o:c) 
 7
 8
 9
10    System.out.printf( " %s%n " ,o); 
11
12 }
 
13
14 }
 
15


事实上,上面这个方法并不通用,它只能打印Collection<Object>类型的集合,象其他的如Collection<String>、Collection<Integer>并不能被打印,因为对象类型不一致。

为了解决这个问题,可以使用通配符:
 1
 2 public   void  printCollection(Collection < >  c) 
 3
 4
 5
 6     for (Object o:c) 
 7
 8
 9
10    System.out.printf( " %s%n " ,o); 
11
12 }
 
13
14 }
 
15
16

Collection<?>被称作未知类型的集合。问号代表各种类型。

上面的读取集合中的数据时,我们采用Object类型。这样做时可以的,因为不管未知类型最终代表何种类型,它的数据都继承Object类,那么再考虑一下下面的代码:
1
2 Collection <?>  c  =   new  ArrayList < String > (); 
3
4 c.add( new  Object());   
5
6

这样做时错误的,因为我们不知道?代表何种类型,所以我们不能直接将Object增加到集合中,这会出现类型不匹配的情况。
 

5.有限制的通配符

考虑下面的代码
 1
 2 class  Man 
 3
 4
 5
 6     public  String name  = ""
 7
 8 }
 
 9
10 class  GoodMan  extends  Man 
11
12
13
14     public  String name  =   ""
15
16 }
 
17
18 class  BadMan  extends  Man 
19
20
21
22     public  String name  =   ""
23
24 }
 
25
26

考虑下面的范型方法:
 1
 2 public   void  printName(List < Man >  men) 
 3
 4
 5
 6     for (Man man:men) 
 7
 8    
 9
10       System.out.println( " 姓名: " +  man.name); 
11
12    }
 
13
14 }
 
15
16


这个范型方法只能显示List<Man>类型的数据,下面的代码允许显示Man和它的子类。
 1
 2 public   void  printName(List < ?  extends   Man >  men) 
 3
 4
 5
 6     for (Man man:men) 
 7
 8    
 9
10       System.out.println( " 姓名: "   +  man.name); 
11
12    }
 
13
14 }
 
15
16

这里使用? extends Man代替Man,表明接受任何Man的子类做为参数。

和前面的代码类似,下面的代码也是不正确的:
 1
 2 public   void  adman(List <?   extends  Man >  men) 
 3
 4
 5
 6    GoodMan good  =   new  GoodMan(); 
 7
 8    good.name  =   " zhupan "
 9
10    men.add(good); 
11
12 }
 
13
14

原因也很简单,因为?代表一切继承Man的类,你并不能保证就一定时GoodMan类。

 

和这种用法类似:
 1
 2 public   void  adman(List <?   super  GoodMan >  men) 
 3
 4
相关文章
相关标签/搜索