1 泛型入门

集合元素过去默认为Object类型,无法指定元素类型,编译时不检查类型,而且每次取出对象都要进行强制类型转换,泛型出现避免了这种臃肿的代码。下列代码会看到编译时不检查元素类型导致的异常。

public class ListErr {
    public static void main(String[] args) {
        List strList = new ArrayList();
        strList.add("人有悲欢离合");
        strList.add("月有阴晴圆缺");
        strList.add(23333);
        //ClassCastException
        strList.forEach(str -> System.out.println(((String) str).length()));
    }
}

泛型用于指定集合存储数据的类型。

List<String> books=new ArrayList<String>();

上述代码定义集合时使用泛型,创建对象时构造器也给出泛型类型,这样显然是多余的。java7做了改进。

List<String> books=new ArrayList<>();

2 深入泛型

  • 2.1定义泛型接口、类

我们可以在定义一个类时允许它使用泛型,通过阅读java提供的集合接口源码可以知道如何定义泛型接口。

//定义接口时指定了一个类型形参E
public interface List<E> extends Collection<E> {
    //在接口中将形参E作为类型使用
       boolean add(E e);
          Iterator<E> itorator;
   // ...
}

在实际使用时,只需要在声明对象时传入E的实参即可 。

  • 2.2 从泛型类派生子类

从泛型类派生子类时,我们可以为泛型指定实参,也可以不使用,注意不要再使用形参T。

public class Apple<T> {
    private T info;
    public T getInfo(){
        return this.info;
    }
}

public class SmallApple extends Apple<String> {
    private String info;
    public String getInfo() {
        return this.info;
    }
}
  • 2.3 并不存在泛型类

    实际上,泛型只是设计来用于方便编程,并不会由于指定类型不同而生成不同的class文件。

    public class GenericTest {

      public static void main(String[] args) {
          List<String> strList = new ArrayList<>();
          List<Integer> intList = new ArrayList<>();
          // true
          System.out.println(strList.getClass() == intList.getClass());
      }

    }

也就是说,不管传入实参是不是一个类型,它们仍然被当成一个类型的数据,不允许在静态成员中使用泛型形参。