Bootstrap

Java泛型

Java中的泛型

​ 只在程序源码中存在,在编译后的字节码文件中,就已经被替换为原来的原始类型(Raw Type,也称为裸类型)了,并且在相应的地方插入了强制转型代码,因此对于运行期的Java语言来说,ArrayList与ArrayList就是同一个类。所以说泛型技术实际上是Java语言的一颗语法糖,Java语言中的泛型实现方法称为类型擦除,基于这种方法实现的泛型被称为伪泛型。

  • 泛型又叫类型化参数,与方法参数类似,泛型也有类型形参类型实参

    public class Main2 {
      public static void main(String[] args) {
          /*这里的String是类型实参*/
          Generic<String> generic = new Generic<>("abc");
          System.out.println(generic.getVal());
      }
    }
    /*这里的T是类型形参*/
    class Generic<T> {
      private T val;
      public Generic(T val) {this.val = val;}
      public T getVal() {return val;}
    }
  • 泛型接口

    interface Generator<T> {
      T create(T val);
    }
    /*在实现接口时,未指定类型实参,需要将泛型声明到类中*/
    class MyGenerator<T> implements Generator<T> {
      private T val;
      @Override
      public T create(T val) {
          return val;
      }
    }
    /*在实现接口时,指定了类型实参*/
    class StringGenerator implements Generator<String> {
      @Override
      public String create(String val) {
          return val;
      }
    }
  • 泛型通配符

    Generic<Integer> generic2 = new Generic<>(123);
    Generic<Number> generic3 = new Generic<>(456);
    generic3 = generic2;// 编译错误,即使Integer是Number的子类,但是不能这样转换
    // ? 是类型实参,表示某种类型
    Generic<?> generic4 = new Generic<>(123);
    System.out.println(generic4.getVal());
    // 由于?属于类型占位符,可以代表任意类型,所以可以这样赋值
    generic4 = generic2;
  • 泛型方法

    /**
    * public 后的 T 表示泛型方法的类型形参,前面例子中的方法不属于泛型方法;这里的T可以是类的泛型的类型    形数也可以是方法自己的类型形参。
    */
    public <T> T genericMethod(Class<T> clazz) throws IllegalAccessException, InstantiationException {
      return clazz.newInstance();
    }
  • 静态泛型方法:由于泛型是在运行时确定实际的类型的,所以不能使用类或接口上的类型形参;因此就应该使用泛型方法

    // 这里的类型形参独立于类上或者接口上声明的类型形参,这里方法返回值前面的类型形参声明必须存在
    public static <E> E getElement(E e) {
      return e;
    }
  • 泛型使用要求

    • 不能使用基本类型(primitive type)
    • 不管该限定是类还是接口,统一都使用关键字extends(上界,类型形参为任何继承或实现自该类)或super(下界,指定类的基类)
    • 可以使用&符号给出多个限定
    • 如果限定既有接口也有类,那么类必须只有一个,并且放在首位置(类优先原则)

  • 使用反射技术来破坏泛型的限制

@Test
public void test() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    // 使用反射来破坏泛型的限制
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.getClass().getMethod("add", Object.class).invoke(list, "234");
    for (int i = 0; i < list.size(); i++) {
        System.out.println(list.get(i));
    }
}
  • 原始类型(Raw Type)

    原始类型就是泛型信息被擦除后,在编译成字节码后变量的真实类型。类型变量被擦除后,使用限定名替换,对于extends多个的限定名的情况,使用第一个限定名替换;没有指定限定名的则使用Object替换。

;