跳转至

Java 泛型

1. 介绍

  什么是泛型,看表面的意思,泛型就是指广泛的、普通的类型。在java中是指把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型。在没泛型之前看以下一个例子

public class genericsDemo {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add(1);
        list.add("cmz");
        list.add(6.66);

        for (int i = 0; i <list.size() ; i++) {
            System.out.println((String)list.get(i));
        }
    }
}
输出
Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap')
    at ArrayListDemo.genericsDemo.main(genericsDemo.java:17)
ArrayList可以存放任意类型,例子中添加了一个String类型,添加了一个Integer类型,再使用时都以String的方式使用,因此程序崩溃了。为了解决类似这样的问题(在编译阶段就可以解决),泛型应运而生。

我们将第一行声明初始化list的代码更改一下,编译器会在编译阶段就能够帮我们发现类似这样的问题。

ArrayList<String> list = new ArrayList<>();
list.add("www");
list.add(123); //编译时候这个地方会报错,因为list里面必须插入的是String 类型。也就是说泛型信息不会进入到运行时阶段。

2. 泛型的使用

  泛型有三种使用方式,分别为:泛型类、泛型接口、泛型方法

2.1 泛型类

  泛型类型用于类的定义中,被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口。最典型的就是各种容器类,如:List、Set、Map。

泛型类的最基本写法

class 类名称 <泛型标识:可以随便写任意标识号,标识指定的泛型的类型>{
  private 泛型标识 /*(成员变量类型)*/ var; 
  .....

  }
}

一个最普通的泛型类

//此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型
//在实例化泛型类时,必须指定T的具体类型
public class Generic<T>{ 
    //key这个成员变量的类型为T,T的类型由外部指定  
    private T key;

    public Generic(T key) { //泛型构造方法形参key的类型也为T,T的类型由外部指定
        this.key = key;
    }

    public T getKey(){ //泛型方法getKey的返回值类型为T,T的类型由外部指定
        return key;
    }
}

Generic.class

package ArrayListDemo;

/**
 * @author summer
 * @create 2020-02-06 21:53
 */
public class Generic<T> {
    private T key;

    public T getKey() {
        return key;
    }

    public void setKey(T key) {
        this.key = key;
    }

    public Generic(T key) {
        this.key = key;
    }

    @Override
    public String toString() {
        return "Generic{" +
                "key=" + key +
                '}';
    }
}

GenericTest.class

package ArrayListDemo;

/**
 * @author summer
 * @create 2020-02-06 21:57
 */
public class GenericTest {
    public static void main(String[] args) {
        //泛型的类型参数只能是类类型(包括自定义类),不能是简单类型
        //传入的实参类型需与泛型的类型参数类型相同,即为Integer.
        Generic<Integer> ge1 = new Generic<>(123);
        System.out.println(ge1);
        System.out.println(ge1.getKey());

        //传入的实参类型需与泛型的类型参数类型相同,即为String.
        Generic<String> ge = new Generic<>("k1");
        System.out.println(ge.getKey());
    }
}

输出

k1
Generic{key=123}
123
定义的泛型类,就一定要传入泛型类型实参么?并不是这样,在使用泛型的时候如果传入泛型实参,则会根据传入的泛型实参做相应的限制,此时泛型才会起到本应起到的限制作用。如果不传入泛型类型实参的话,在泛型类中使用泛型的方法或成员变量定义的类型可以为任何的类型。

2.2 泛型接口

  泛型接口与泛型类的定义及使用基本相同。泛型接口常被用在各种类的生产器中,可以看一个例子

//定义一个泛型接口
public interface Generator<T> {
    public T next();
}