一.定义泛型接口、类

1.泛型接口
//定义接口时指定了一个类型形参E
public interface List<E>{
  //在该接口里,E可以作为类型使用
  //下面方法可以使用E作为参数类型
  void add(E e);
  ...
}
2.泛型类
//定义Apple类时使用了泛型声明
public class Apple<T>{
  //使用T类型形参定义实例变量
  private T info;
  public Apple(T info){
  }
}
二.定义泛型方法
1.格式
修饰符<T,S> 返回值类型 方法名(参数列表){方法体。。。}
2.例子
public class GenericMethodTest{
  //声明一个泛型方法,该泛型方法中带一个T类型形参
  static <T> void fromArrayToCollection(T[] a,Collection<T> c){
    for(T o:a){
      c.add(o);
    }
  }
}
三.类型通配符(?)
1.通配符?表示未知的类型,可以匹配任何类型。
2.用法
public void test(List<?> c){
  for(int i=0;i<c.size();i++){
    System.out.println(c.get(i));
  }
}
**

1.List<?>表示元素类型未知的List,它是所有泛型List的父类。

2.这种写法适用于任何支持泛型声明的接口和类,如Set<?>,Collection<?>,Map<?,?>

3.这种带通配符的List仅表示它是各种泛型的父类,并不能将元素加入到其中。如:

List<?> c = new ArrayList<String>();
  //下面引起编译报错
  c.add(new String(""));

因为程序无法确定c集合中元素的类型,所以不能向其添加对象。  

四.设定上下限

1.设定上限

public class Canvas{
  //同时在画布上绘制多个形状
  public void drawAll(List<? extends Shape> shapes){
    for(Shap s:shaps){
      s.draw(this);
    }
  }
}
//表明T类型必须是Number类或其子类,并必须实现java.io.Serializable接口
public class Apple<T extends Number & java.io.Serializable>{
}

2.设定下限

public class MyUtils{
  //下面dest集合元素的类型必须与src集合元素的类型相同,或其父类
  public static<T> T copy(Collection<? super T> dest,Collection<T> src){
    T last = null;
    for(T ele:src){
      last = ele;
      dest.add(ele);
    }
    return T;
  }
}

五.泛型方法与类型通配符的关系

1.大多数时候都可以使用泛型方法来代替类型通配符:如Java的Collection接口中有两个方法

public interface Collection<E>{
  boolean containsAll(Collection<?> c);
  boolean addAll(Collection<? extends E> c);
  ...
}
可以改为:
public interface Collection<E>{
  <T> boolean containsAll(Collection<T> c);
  <T extends E>boolean addAll(Collection<T> c);
  ...
}
**

1.上面两个方法中类型形参T只使用一次,类型形参T产生的唯一效果是可以在不同的调用点传入不同的实际类型,对于这种情况,应该使用通配符。

2.泛型方法允许类型形参被用来表示方法的一个或多个参数之间的类型依赖关系,或者方法返回值与参数之间的类型依赖关系。如果没有这样的类型依赖关系,就不应该使用泛型方法。

2.泛型方法和通配符可同时使用

如java的Collections.copy()方法:

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

**注意上面的类型形参S,它仅适用了一次,其他参数的类型、方法返回值的类型都不依赖于它,那么类型形参S就没有存在的必要,即可以使用通配符来代替S。