Java基础复习 —— 泛型

泛型

简介

  1. Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。

  2. 泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数

  3. 泛型的作用是可以在类声明时,通过标识表示类中某个属性的类型,或者某个方法的返回值类型,或者是参数类型

泛型的好处

  1. 减少了类型转换的次数,提高效率

  2. 编译时,检查添加元素的类型,提高安全性

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

  3. 编写的代码可以被不同类型的对象所复用

泛型的声明

interface 接口名 <T> {} // 泛型接口 
class 类名 <K,V> {} // 泛型类
  1. 其中,T,K 和 V 是类型标识,不代表值
  2. 任意字母都可以,通常使用
    • T - Type(Java 类)
    • E - Element (在集合中使用,因为集合中存放的是元素)
    • K - Key(键)
    • V - Value(值)
    • N - Number(数值类型)
    • - 表示不确定的 java 类型

泛型的实例化

ArrayList<String> strList = new ArrayList<String>();
Iterator<Custom> iterator = customs.iterator();

泛型使用的注意事项和细节

  • 注意类型参数只能代表引用类型,不能是基本数据类型(像 int、double、char 等)。

  • 给泛型指定具体类型后,可以传入该类型的或其子类类型

    public class Generic02 {
        public static void main(String[] args) {
            Cat<A> cat1 = new Cat<>(new A()); // 传入A类
            Cat<A> cat2 = new Cat<>(new B()); // 构造方法传入A的子类B
        }
    }
    
    class A {
    }
    
    class B extends A {
    }
    
    class Cat<E> {
        E e;
    
        public Cat(E e) {
            this.e = e;
        }
    }
    
  • 如果不指明具体类型,默认为 Object

    ArrayList arrayList = new ArrayList();//等价 ArrayList<Object> arrayList = new ArrayList<Object>()
    
  • 可以简写

    ArrayList<Integer> list1 = new ArrayList<Integer>();
    List<Integer> list2 = new ArrayList<>(); // 推荐使用简写
    

自定义泛型

自定义泛型类

class 类名 <T, R...> { // 可以是一个或多个泛型参数
    . . .
}
  1. 普通成员可以使用泛型(属性,方法)
  2. 使用泛型的数组不能初始化
  3. 静态方法中不能使用类的泛型
  4. 泛型类的类型,是在创建对象时确定的(创建对象时,需要指定确定的类型)
  5. 如果创建对象时,没有指定类型,默认为Object
class Cat<T, R, M> {
    String name;
    T t;
    R r;
    M m;

	// T[] ts = new T[3]; 
    // Type parameter 'T' cannot be instantiated directly
    // 因为数组在 new 时不能确定 T 的类型, 就无法在内存开空间
    T[] ts; // 可以声明

	//static R r2; 
    // 因为静态是和类相关的, 在类加载时, 对象还没有创建
    // /所以, 如果静态方法和静态属性使用了泛型, JVM 就无法完成初始化
}

自定义泛型接口

interface 接口名 <T, R, ...> {
}
  1. 接口中,静态成员也不能使用泛型
  2. 泛型接口的类型,在继承或者实现接口时确定
  3. 没有指定类型,默认Object
interface IUsb<U, R> {
//    U u ;
    // 接口中成员默认 static,不能这样使用

    // 抽象方法中, 可以使用接口泛型
    R get(U u);

    void hi(R r);

    void run(R r1, R r2, U u1, U u2);

    //在 jdk8 中, 可以在接口中, 默认方法, 也是可以使用泛型
    default R method(U u) {
        return null;
    }
}

interface AA extends IUsb<Integer, String> {
}

//子接口泛型可以比父接口多,子类泛型可以比父类多
interface BB<U, R,V> extends IUsb<Double, String> {

}

//在继承接口 指定泛型接口的类型
interface CC<U, R> extends IUsb<U, R> {

}

//没有指定类型, 默认为 Object
// 等价于 interface DD extends IUsb<Object,Object>
interface DD extends IUsb {

}

// 实现接口时, 直接指定泛型接口的类型
class EE implements IUsb<Double, Float> {

    @Override
    public Float get(Double aDouble) {
        return null;
    }

    @Override
    public void hi(Float aFloat) {

    }

    @Override
    public void run(Float r1, Float r2, Double u1, Double u2) {

    }
}

自定义泛型方法

修饰符 <T, R> 返回类型 方法名(参数列表){
    
}
  1. 泛型方法,可以定义在普通类中,亦可以定义在泛型类中

  2. 当泛型方法被调用时,类型会确定

  3. public void eat(E e){} 修饰符之后没有泛型标识符 <T,...> ,eat方法不是泛型方法,而是使用了泛型

    public class CustomGenericMethod01 {
        public static void main(String[] args) {
    
            new Car().fly("bmw", 10012); // //当调用方法时, 传入参数, 编译器, 就会确定类型
            Fish<String, ArrayList> fish = new Fish<>();
            fish.hello("hi", 11.2F);
        }
    }
    
    // 普通类
    class Car {
        public  void run() {
        }
    
        public <T, E> void fly(T t, E e){
            System.out.println(t.getClass());
            System.out.println(e.getClass());
        }
    }
    
    //泛型类
    class Fish<T, E> {
    
        public  void run() {
        }
    
        // 泛型方法
        public <U, M> void fly(U u, M m){
            System.out.println(u.getClass());
            System.out.println(m.getClass());
        }
    
        // 泛型方法, 可以使用类声明的泛型, 也可以使用自己声明泛型
        public<K> void hello(T t, K k) {
            System.out.println(t.getClass());//ArrayList
            System.out.println(k.getClass());//Float
        }
    }
    

泛型的继承和通配符

  1. 泛型不具备继承性

    List<Object> strings = new ArrayList<String>(); // 错误 不兼容的类型

  2. <?> 支持任意泛型类型

  3. <? extends A> : 支持A类及A的子类,规定了泛型的上限

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

public class GenericHeritance {
    public static void main(String[] args) {

        Object o = new String("xx");
        //泛型没有继承性
        //List<Object> list = new ArrayList<String>();
        
        //举例说明下面三个方法的使用
        List<Object> list1 = new ArrayList<>();
        List<String> list2 = new ArrayList<>();
        List<AA> list3 = new ArrayList<>();
        List<BB> list4 = new ArrayList<>();
        List<CC> list5 = new ArrayList<>();

        //如果是 List<?> c , 可以接受任意的泛型类型
        printCollection1(list1);
        printCollection1(list2);
        printCollection1(list3);
        printCollection1(list4);
        printCollection1(list5);

        //List<? extends AA> c: 表示 上限, 可以接受 AA 或者 AA 子类
        // printCollection2(list1);//×
        // printCollection2(list2);//×
        printCollection2(list3);//√
        printCollection2(list4);//√
        printCollection2(list5);//√

        //List<? super AA> c: 支持 AA 类以及 AA 类的父类, 不限于直接父类
        printCollection3(list1);//√
        //printCollection3(list2);//×
        printCollection3(list3);//√
        //printCollection3(list4);//×
        //printCollection3(list5);//×

    }

    // List<?> 表示 任意的泛型类型都可以接受
    public static void printCollection1(List<?> c) {
        for (Object object : c) { // 通配符, 取出时, 就是 Object
            System.out.println(object);
        }
    }

    //
    //? extends AA 表示 上限, 可以接受 AA 或者 AA 子类
    public static void printCollection2(List<? extends AA> c) {
        for (Object object : c) {
            System.out.println(object);
        }
    }

    // ? super 子类类名 AA:支持 AA 类以及 AA 类的父类, 不限于直接父类,
    public static void printCollection3(List<? super AA> c) {
        for (Object object : c) {
            System.out.println(object);
        }
    }


}

class AA {
}

class BB extends AA {
}

class CC extends BB {
}
posted @ 2023-07-07 16:51  墨染启明  阅读(21)  评论(0编辑  收藏  举报