java-泛型整理

背景:

类型转换中的ClassCastException,JDK5引入,JDK7后<>中的类型可以省略

泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。
也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。

好处:

编译时类型检查保证类型安全,消除强制类型转换,代码复用

定义泛型类

/**
 * 泛型类的定义语法:
 * class ClassName <泛型标识1,泛型标识2,泛型标识3...>{
 *     private 泛型标识 变量名
 * }*/
public class Generic<T>{

    /**
     * 常用的泛型标识有T,E,K,V
     */
    private T key;

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

    public T getKey() {
        return key;
    }

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

使用泛型类

       /**
         * 使用语法:
         * 类名<具体数据类型>  对象名 = new 类名<>();
         * 泛型是在创建对象的时候,来指定操作的具体类型
         * 不支持基本数据类型,只支持引用类型
         * 如果不指定具体的数据类型,默认是Object类型
         * 不同类型创建的泛型对象,都是相同的类型,与泛型类型无关,也就是getClass()结果相同
         *
         */
        Generic<String> strGeneric = new Generic<>("a");
        Generic<Integer> intGeneric = new Generic<>(1);
        System.out.println(strGeneric.getClass()==intGeneric.getClass());   ---true

 泛型类的子类

子类如果也是泛型类,子类和父类泛型类型要一致;因为子类加载前要先加载父类,如果不一致,父类不清楚是什么类型,会直接报错,无法加载

子类如果也是泛型类,至少要有一个和父类泛型类型一致,子类还可以有多个泛型类型

子类如果不是泛型类,父类要指定具体的泛型类型;

public class Parent<E> {
    private E value;

    public E getValue() {
        return value;
    }
}
/**
 * 父类不指定类型,则默认泛型类型是Object
 */
public class Child1<T> extends Parent{
    /**
     * 返回的是Object
     */
    @Override
    public Object getValue() {
        return super.getValue();
    }
}

/**
 * 子类是泛型,那么子类和父类的泛型类型必须一致
 * 子类可以有多个泛型类型
 */
public class Child1<E,T,K> extends Parent<E>{

    @Override
    public E getValue() {
        return super.getValue();
    }
}

/**
 * 子类不是泛型类,父类必须明确数据类型
 * 因为加载子类的时候需要先加载父类,父类不知道是什么类型,加载报错
 */
public class Child2 extends Parent<E>{  --------报错

    @Override
    public E getValue() {
        return super.getValue();
    }
}

泛型接口

和泛型类相似,定义语法:

interface 接口名称<泛型标识1,泛型标识2,泛型标识3>{
    泛型标识  方法名();
}

实现类如果是泛型类,实现类和接口的泛型类型要一致

实现类如果不是泛型类型,接口要明确泛型类型

例子和泛型类的差不多

泛型方法

语法:

修饰符 <T,K,E...> 返回类型  方法名(参数列表){
    方法体
}

找到一张很好的图:

以<T>为例

修饰符和返回类型之间的<T>声明此方法是泛型方法,只有声明了<T>的方法才是泛型方法

泛型类中使用了泛型类型的方法不是泛型方法(因为这个泛型类型其实只是返回类型)

<T>表明该方法将使用泛型类型T,此时才可以在泛型方法中使用类型T

   /**
     * 泛型方法
     * @param list  参数
     * @param idx   参数
     * @param <E>   泛型方法的标识,具体类型由调用方法的时候来指定
     * @return
     */
    public <E> E getProduct(ArrayList<E> list,int idx){
        return list.get(idx);
    }

 类型通配符

类型通配符就是能代表任意类型的一个符号,比如 ?

@Data
public class Box<E>{
    private E ball;
}

public class Test {

    public static void main(String[] args) {
        Box<Number> box1 = new Box<>();
        box1.setBall(100);
        showBox(box1);

        //Integer继承的Number,也不能直接调用
        Box<Integer> box2 = new Box<>();
        box2.setBall(100);
        //报错
        showBox(box2);   
    }

    public static void showBox(Box<Number> box){
        Number ball = box.getBall();
        System.out.println(ball);
    }
}

类型通配符上限

语法:<? extends 实参类型>

表示使用时泛型的类型只能是实参类型或它的子类类型

public class Test {

    public static void main(String[] args) {
        ArrayList<A> listA = new ArrayList<A>();
        ArrayList<B> listB = new ArrayList<B>();
        ArrayList<C> listC = new ArrayList<C>();
        //报错
        print(listA);
        print(listB);
        print(listC);

    }

    public static void print(ArrayList<? extends B> list){
        //do something
    }
}

类型通配符下限

语法:<? super 实参类型>

表示使用时,泛型类型只能是实参类型或它的父类类型

/**
 * 假设类  C extends B extends A
 */
public class Test {

    public static void main(String[] args) {
        ArrayList<A> listA = new ArrayList<A>();
        ArrayList<B> listB = new ArrayList<B>();
        ArrayList<C> listC = new ArrayList<C>();
        print(listA);
        print(listB);
        //报错
        print(listC);

    }

    public static void print(ArrayList<? super B> list){
        //do something
    }
}

 类型擦除

无限制类型的情况下擦除后是Object类型,也就是泛型类型的根父类

public class Box<E>{
    
    private E ball;

    public E getBall() {
        return ball;
    }

    public Box(E ball) {
        this.ball = ball;
    }
}
///////////类型擦除的结果///////////////
public class Box {

    private Object ball;

    public Object getBall() {
        return ball;
    }

    public Box(Object ball) {
        this.ball = ball;
    }
}

上限通配符情况下,擦出后是上限类型

public class Eraser<T extends Number> {
    
    private T key;

    public T getKey() {
        return key;
    }

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

/////////////类型擦除后////////////////
public class Eraser{

    private Number key;

    public Number getKey() {
        return key;
    }

    public Eraser(Number key) {
        this.key = key;
    }
}

 泛型方法的类型擦除

   public <T extends Number> T getValue(T value){
       return value;
   }
  ///////类型擦除后/////////////
   public Number getValue(Number value){
       return value;
   }

 反射常用的泛型类

Class<T>

Constructor<T>

 

 

posted @ 2022-03-30 23:07  鼠标的博客  阅读(48)  评论(0编辑  收藏  举报