Java 泛型(1)

JDK1.5给Java语言引入了几个新的扩展,其中之一就是泛型。你可能已经从其他的语言中了解到了泛型结构,最著名的就是C++模板。Java泛型和它有很多类似的地方,但是也有很多重要的不同点。

Java泛型应用最普遍的地方就是各种容器类型,即Collection继承树。

一、定义泛型:public interface List<E>{void add(E x); Iterator<E> iterator();}

泛型可以是类,也可以是接口,还可以是方法。

和普通类或者接口的定义不同,泛型定义时需要一个形式类型参数(E),放到尖括号内。然后在定义体中就可以像使用普通类型一样,使用这个形式类型(有一定限制,后面会讲)。

二、泛型和子类型

假设Foo继承于Bar,G是某个泛型,那么虽然Foo是Bar的子类型,但是G<Foo>并不是G<Bar>的子类型。这点和我们的直觉相违背,一定要注意。

三、通配符?

1、?表示类型参数是不确定(unknown),即可以是任何类型,如Collection<?>是任何集合类的父类,表示这个集合的元素可以是任何类型。对应unknown类型的集合,我们可以取出元素并且赋值给Object对象,但是不能给这个集合添加Object类型的对象,如Collection<?> c = new ArrayList<String>(); 那么c.add(new Object())是非法的。

2、有限制的通配符,如 public void drawAll(List<? extends Shape> shapes) {...},?表示的类型是unknown,不过有限制,只能是Shape或者他的子类,如List<Shape>, List<Circle>, List<Square>等。注意我们使用了extends关键字,我们说Shape是通配符?的上界。

使用通配符带来了上面的灵活性,也付出了一些代价,那就是你不能对上面的shape进行写操作,只能读取。如下例子是非法的,这是因为?还有可能是Rectangle的子类。

public void addRectangle(List<? extends Shape> shapes) {
    // Compile-time error!
    shapes.add(0, new Rectangle());
}

3、下界通配符:使用super关键字

public static <T> T writeAll(Collection<T> coll, Sink<? super T> snk) {
    ...
}
Sink<Object> s;
Collection<String> cs;
String str = writeAll(cs, s); // Yes!

四、泛型方法

编写一个把数组添加到集合里面去的通用方法:

错误方法:

static void fromArrayToCollection(Object[] a, Collection<?> c) {
    for (Object o : a) { 
        c.add(o); // compile-time error
    }
}

正确方法:我们调用下面这个方法,只要满足数组元素的的类型是集合元素的类型或者子类就可以了。如:

static <T> void fromArrayToCollection(T[] a, Collection<T> c) {

    for (T o : a) {

     c.add(o); // Correct 

  }

}

五、什么时候使用通配符,什么时候使用泛型方法

通配符被设计用来支持灵活的子类型,泛型方法用来描述一个方法的参数及其返回值类型之间的依赖关系,如果没有这种依赖关系,那么不要使用泛型方法,应该使用通配符。

当然,通配符也可以和泛型方法串联使用,如:

class Collections {
    public static <T> void copy(List<T> dest, List<? extends T> src) {
    ...
}


 

原文地址:https://www.cnblogs.com/winson/p/4123638.html