技术开发 频道

多角度看 Java 中的泛型


IT168技术文档】 
    泛型中的子类型 

    在 Java 语言中,我们可以将某种类型的变量赋值给其父类型所对应的变量,例如,String 是 Object 的子类型,因此,我们可以将 String 类型的变量赋值给 Object 类型的变量,甚至可以将 String [ ] 类型的变量(数组)赋值给 Object [ ] 类型的变量,即 String [ ] 是 Object [ ] 的子类型。 

    上述情形恐怕已经深深地印在了广大读者的脑中,对于泛型来讲,上述情形有所变化,因此请广大读者务必引起注意。为了说明这种不同,我们还是先来分析一个小例子,代码如下所示:
1 List<String> ls = new ArrayList<String>(); 2 List<Object> lo = ls; 3 lo.add(new Integer()); 4 String s = ls.get(0);
     上述代码的第二行将 List<String> 赋值给了 List<Object>,按照以往的经验,这种赋值好像是正确的,因为 List<String> 应该是 List<Object> 的子类型。这里需要特别注意的是,这种赋值在泛型当中是不允许的!List<String> 也不是 List<Object> 的子类型。 

    如果上述赋值是合理的,那么上面代码的第三行的操作将是可行的,因为 lo 是 List<Object>,所以向其添加 Integer 类型的元素应该是完全合法的。读到此处,我们已经看到了第二行的这种赋值所潜在的危险,它破坏了泛型所带来的类型安全性。 

    一般情况下,如果 A 是 B 的子类型,C 是某个泛型的声明,那么 C<A> 并不是 C<B> 的子类型,我们也不能将 C<A> 类型的变量赋值给 C<B> 类型的变量。这一点和我们以前接触的父子类型关系有很大的出入,因此请读者务必引起注意。 

    泛化方法和受限类型参数 

    在这一部分我们将讨论有关泛化方法(generic method )和受限类型参数(bounded type parameter)的内容,这是泛型中的两个重要概念,还是先来分析一下与此相关的代码。
1 interface Comparable<A> { 2 public int compareTo(A that); 3 } 4 5 class Byte implements Comparable<Byte> { 6 private byte value; 7 public Byte(byte value) {this.value = value;} 8 public byte byteValue() {return value;} 9 public int compareTo(Byte that) { 10 return this.value - that.value; 11 } 12 } 13 14 class Collections { 15 public static <A implements Comparable<A>> 16 A max (Collection<A> xs) { 17 Iterator<A> xi = xs.iterator(); 18 A w = xi.next(); 19 while (xi.hasNext()) { 20 A x = xi.next(); 21 if (w.compareTo(x) < 0) w = x; 22 } 23 return w; 24 } 25 }
    这里定义了一个接口 Comparable<A>,用来和 A 类型的对象进行比较。类 Byte 实现了这个接口,并以它自己作为类型参数,因此,它们自己就可以和自己进行比较了。 

    第 14 行到第 25 行的代码定义了一个类 Collections,这个类包含一个静态方法 max(Collection<A> xs),它用来在一个非空的 Collection 中寻找最大的元素并返回这个元素。这个方法的两个特点就是它是一个泛化方法并且有一个受限类型参数。 

    之所以说它是泛化了的方法,是因为这个方法可以应用到很多种类型上。当要将一个方法声明为泛化方法时,我们只需要在这个方法的返回类型(A)之前加上一个类型参数(A),并用尖括号(< >)将它括起来。这里的类型参数(A)是在方法被调用时自动实例化的。例如,假设对象 m 的类型是 Collection<Byte>,那么当使用下面的语句: 


    Byte x = Collections.max(m); 

    调用方法 max 时,该方法的参数 A 将被推测为 Byte。 

    根据上面讨论的内容,泛化方法 max 的完整声明应该是下面的形式: 

    < A > A max (Collection<A> xs) { 
    max 的方法体 
    } 

    但是,我们见到的 max 在 < A > 中还多了 "implements Comparable<A>" 一项,这是什么呢?这就是我们下面将要谈到的"受限的类型参数"。在上面的例子中,类型参数 A 就是一个受限的的类型参数,因为它不是泛指任何类型,而是指那些自己和自己作比较的类型。例如参数可以被实例化为 Byte,因为程序中有 Byte implements Comparable<Byte> 的语句,参见第 5 行。这种限制(或者说是范围)通过如下的方式表示,"类型参数 implements 接口",或是 "类型参数 extend 类",上面程序中的"Byte implements Comparable<Byte>"就是一例。
0
相关文章