2023-12-12 泛型的补充

2023-12-11  本文已影响0人  大也

1.泛型 定义 集合类 容器 存的是什么类型的对象

2.<>() 类型推断
ArrayList<String> list2 = new ArrayList<>();

image.png

代码简化
// Set<Map.Entry<String,Integer>> entrySet = map.entrySet();
// Iterator<Map.Entry<String, Integer>> iterator = entrySet.iterator();

    var entrySet = map.entrySet();
    var iterator = entrySet.iterator();
image.png

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
类 E 上声明 方法内用到E的 都是同类型

  1. //不可以在静态方法中使用类的泛型

泛型方法可以根据需要声明为static的

  1. 类SuperA是类A的父类,则G<SuperA> 与 G<A>的关系:G<SuperA> 和 G<A>是并列的两个类,没有任何子父类的关系。
    比如:ArrayList<Object> 、ArrayList<String>没有关系
  2. 类SuperA是类A的父类或接口,SuperA<G> 与 A<G>的关系:SuperA<G> 与A<G> 有继承或实现的关系。
    即A<G>的实例可以赋值给SuperA<G>类型的引用(或变量)
    比如:List<String> 与 ArrayList<String>
class A<T>{

}

interface B<T1,T2>{
}

    public <E> E method(E e){
        return null;
    }

public <E> ArrayList<E> copyFromArrayToList(E[] arr){
        ArrayList<E> list = new ArrayList<>();
        for(E e : arr){
            list.add(e);
        }

        return list;
    }
class Person<T> {
    // 使用T类型定义变量
    private T info;
    // 使用T类型定义一般方法
    public T getInfo() {
        return info;
    }
    public void setInfo(T info) {
        this.info = info;
    }
    // 使用T类型定义构造器
    public Person() {
    }
    public Person(T info) {
        this.info = info;
    }
    // static的方法中不能声明泛型
    //public static void show(T t) {
    //
    //}
    // 不能在try-catch中使用泛型定义
    //public void test() {
        //try {
        //
        //} catch (MyException<T> ex) {
        //
        //}
    //}
}
class Father<T1, T2> {
}
// 子类不保留父类的泛型
// 1)没有类型 擦除
class Son1 extends Father {// 等价于class Son extends Father<Object,Object>{
}
// 2)具体类型
class Son2 extends Father<Integer, String> {
}
// 子类保留父类的泛型
// 1)全部保留
class Son3<T1, T2> extends Father<T1, T2> {
}
// 2)部分保留
class Son4<T2> extends Father<Integer, T2> {
}
class Father<T1, T2> {
}
// 子类不保留父类的泛型
// 1)没有类型 擦除
class Son<A, B> extends Father{//等价于class Son extends Father<Object,Object>{
}
// 2)具体类型
class Son2<A, B> extends Father<Integer, String> {
}
// 子类保留父类的泛型
// 1)全部保留
class Son3<T1, T2, A, B> extends Father<T1, T2> {
}
// 2)部分保留
class Son4<T2, A, B> extends Father<Integer, T2> {
}
  1. 自定义泛型类\接口
    1.1 格式
    class A<T>{

}

interface B<T1,T2>{
}

1.2 使用说明
① 我们在声明完自定义泛型类以后,可以在类的内部(比如:属性、方法、构造器中)使用类的泛型。
② 我们在创建自定义泛型类的对象时,可以指明泛型参数类型。一旦指明,内部凡是使用类的泛型参数的位置,都具体化为指定的类的泛型类型。
③ 如果在创建自定义泛型类的对象时,没有指明泛型参数类型,那么泛型将被擦除,泛型对应的类型均按照Object处理,但不等价于Object。

1.3 注意点
① 泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如:<E1,E2,E3>
② JDK7.0 开始,泛型的简化操作:ArrayList<Fruit> flist = new ArrayList<>();
③ 如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象。
④ 不能使用new E[]。但是可以:E[] elements = (E[])new Object[capacity];
参考:ArrayList源码中声明:Object[] elementData,而非泛型参数类型数组。
⑤ 在类/接口上声明的泛型,在本类或本接口中即代表某种类型,但不可以在静态方法中使用类的泛型。
⑥ 异常类不能是带泛型的。

  1. 自定义泛型方法
    2.1 问题:在泛型类的方法中,使用了类的泛型参数。那么此方法是泛型方法吗?

2.2 格式
权限修饰符 <T> 返回值类型 方法名(形参列表){ //通常在形参列表或返回值类型的位置会出现泛型参数T

}

2.3 举例
public <E> E method(E e){
}

2.4 说明

声明泛型方法时,一定要添加泛型参数<T>
泛型参数在方法调用时,指明其具体的类型
泛型方法可以根据需要声明为static的
泛型方法所属的类是否是一个泛型类,都可以。

03-泛型在继承上的体现

  1. 类SuperA是类A的父类,则G<SuperA> 与 G<A>的关系:G<SuperA> 和 G<A>是并列的两个类,没有任何子父类的关系。

比如:ArrayList<Object> 、ArrayList<String>没有关系

  1. 类SuperA是类A的父类或接口,SuperA<G> 与 A<G>的关系:SuperA<G> 与A<G> 有继承或实现的关系。
    即A<G>的实例可以赋值给SuperA<G>类型的引用(或变量)

比如:List<String> 与 ArrayList<String>

04- 通配符: ?

  1. 通配符: ?

  2. 使用说明:

举例:ArrayList<?>

G<?> 可以看做是G<A>类型的父类,即可以将G<A>的对象赋值给G<?>类型的引用(或变量)

  1. 读写数据的特点(以集合ArrayList<?>为例说明)

读取数据:允许的,读取的值的类型为Object类型
写入数据:不允许的。特例:写入null值。

  1. 有限制条件的通配符
    List<? extends A> : 可以将List<A>或List<B>赋值给List<? extends A>。其中B类是A类的子类。
    List <? super A> :可以将List<A>或List<B>赋值给List<? extends A>。其中B类是A类的父类。

  2. 有限制条件的统配符的读写操作(难、了解)
    技巧:开发中,遇到了带限制条件的通配符,在赋值时,如果没报错,那就正常使用。
    如果报错了,知道不能这样写。改改!

上一篇 下一篇

猜你喜欢

热点阅读