Java基础笔记(4)-泛型

泛型基础

泛型定义

  1. 泛型又称为参数化类型,是在JDK 5之后出现的新特性,解决数据类型的安全性问题

  2. 在类声明或实例化的时候只需要指定好需要的具体的类型即可

  3. Java泛型可以保证如果程序在编译的时候没有发出警告,运行时就不会产生ClassCastException异常。同时代码更加简洁、健壮

  4. 泛型的作用是:可以在类声明的时候通过一个标识符表示类中某个属性的类型,或者某个方法返回值的类型,或者是参数类型(类似于模板)

    1
    2
    3
    class Person<T> {
    T s; //对应中括号中的T
    }

泛型的声明

1
2
interface 接口<T>{};
class 类<K,V>{};
  • 其中,T,K,V等不代表值,而是代表类型
  • 任意字母都可以,常用T来表示,是Type的缩写
  • Java库使用变量E来表示集合的元素类型;K和V分别表示键和值;T、S、U表示任意类型

注意事项:

  1. T,E只能是引用类型

  2. 在指定泛型具体类型之后,可以传入该类型或其子类类型

  3. 如果不给定泛型的具体类型,则默认泛型类型为Object

  4. 在实际开发的时候可以简写,在new后面的可以简写

    1
    2
    ArrayList<Integer> list = new ArrayList<>();
    List<Integer> list = new ArrayList<>();

自定义泛型

自定义泛型类:

1
class 类名<T,R,...>{};
  1. 普通成员可以使用泛型(属性、方法)
  2. 使用泛型的数组,不能初始化(因为在new的时候并不知道应该开多少空间)
  3. 静态方法中不能使用类的泛型(因为静态的在类加载的时候就创建了,与对象无关)
  4. 泛型类的类型,是在创建对象时确定的(因为创建对象的时候,需要指定确定类型)
  5. 如果在创建对象的时候,没有指定类型,默认为Object

自定义泛型接口:

1
interface 接口名<T,R,...>{};
  1. 接口中,静态成员也不能使用泛型(与泛型类的规定一样)(接口中的属性都是静态的)

  2. 泛型接口的类型,在继承接口或者实现接口的时候确定

  3. 没有指定类型,默认为Object

    1
    2
    3
    4
    class C implenments I{};
    / /等价于
    class C implentments I<Object, Object>{};
    // 但是建议使用下面这种方式,更加规范

自定义泛型方法:

1
2
3
4
修饰符<T,R,...> 返回类型 方法名(参数列表){};
public <T, R> void fly(T t, R r){};//泛型方法
// 定义的泛型是提供给方法使用的
// 在调用方法的时候,会根据传入的参数自动确定对应的类型
  1. 泛型方法,可以定义在普通类中,也可以定义在泛型类当中
  2. 当泛型方法被调用的时候,会确定类型
  3. public void eat(E e){},修饰符后面没有尖括号,这是使用了类声明的泛型,而不是泛型方法
  4. 泛型方法可以使用类声明的泛型,也可以使用自己定义的泛型

泛型的继承和通配符

  1. 泛型不具备继承性

    1
    List<Object> list = new ArrayList<String>();//这样书写是错误的
  2. <?>: 支持任意泛型类型

  3. <? extends A>:支持A类以及A类的子类,规定了泛型的上限(实现接口的限制也是使用extends关键字)

  4. <? super A>:支持A类以及A类的父类,不限于直接父类,规定了泛型的下限

泛型擦除

泛型擦除:虚拟机并没有泛型类型对象,所有的对象都属于一个普通的类。无论何时定义一个泛型类型,都会自动提供一个相应的原始类型。类型变量会被擦除,被替换为限定类型(通配符的限制),或者无限定的变量替换为Object

  • 虚拟机中没有泛型,只有普通的类和方法
  • 所有的类型参数都会替换为它们的限定类型
  • 合成桥方法来保持多态
  • 为保持类型安全性,必要时会插入强制类型转换

泛型的限制

  1. 不能使用基本数据类型实例化类型参数

  2. 运行时类型查询只适用于原始类型,不能查询泛型类型

  3. 不能创建参数化类型的数组

    1
    new Pair<String>[10]; // ERROR
  4. 不能实例化类型变量

    1
    2
    3
    4
    public Pair(){
    first = new T();
    second = new T();
    }// ERROR
  5. 不能构造泛型数组

    1
    T[] mm = new T[2]; // ERROR
  6. 泛型类的静态上下文中类型变量无效

    • 不能在静态字段或方法中引用类型变量,即不能使用带有类型变量的静态字段和方法
  7. 不能抛出或捕获泛型类的实例

    • 既不能抛出也不能捕获泛型类的对象
    • 泛型类扩展Throwable是不合法的
    • catch子句中不能使用类型变量
  8. 可以取消对检查型异常的检查

    使用泛型类、擦除以及@SuppressWarnings注解

    1
    2
    3
    4
    @SuppressWarnings("unchecked")
    static <T extends Throwable> void throwAs(Throwable t) throws T{
    throw (T) t;
    }

Java基础笔记(4)-泛型
http://example.com/2022/09/03/Java基础笔记-4-泛型/
作者
EverNorif
发布于
2022年9月3日
许可协议