写点什么

由点到面贯穿整个 Java 泛型理解

作者:知识浅谈
  • 2022 年 6 月 24 日
  • 本文字数:2763 字

    阅读完需:约 9 分钟

由点到面贯穿整个Java泛型理解

泛型概述

Java 泛型(generics)是 DK5 中引入的一个新特性,泛型提供了编译时类型安全监测机制,该机制允许我们在编译时检测到非法的类型数据结构。

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

如我们经常使用的 ArrayList 中的使用 E 表示泛型的形参,需要我们传递指定实际的类型。


如果不指定默认是 Object 类型,Object 不能强转为其本身的子类型,所以出现 java.lang.Object 无法转换为 java.lang.String。


泛型类和接口

泛型类

1、泛型类的定义语法


2、常用的泛型标识:T、E、K、V

泛型标识可以作为「成员变量的类型定义」标识和函数的「返回类型标识」「成员方法的参数类型标识」

  class Test<T>{ //T创建对象的时候指定数据类型      private T a;      public T getA(T b){          return a;      }  }    //具体的实现如下:  Test<Integer> t = new Test<>();//使用Integer类型指定 T 具体是什么
复制代码

3、 泛型类相关知识

  • 泛型类在创建对象的时候,来指定操作的具体类型

  • 如果在创建对象的时候没有指定具体类型,将会按照 Object 类型操作。

  • 泛型类不支持传入基本类型,因为传入的类型需要时 Object 的子类,在类型擦除的时候,如果没有 extends,super,会默认把泛型参数变为 Object,具体泛型擦除看下边

  • 泛型类型在逻辑上可以看成是不同数据类型,但实际上事相同的类型

  • 因为使用了泛型,我们可以在一个类中使用不同的数据类型如:Integer,String 等

泛型子类

1、子类是泛型类

父类是泛型类,子类也是泛型类,子类中的泛型变量要有一个和父类的泛型要保持一致

class Test<T>{    private T a;    public T getA(T b){        return a;    }}
class Son1<T,K> extends Test<T>{ //如果父类是泛型类,子类要有一个泛型变量和父类保持一致}class Son2<K> extends Test<T>{ //报错:不保持一致会报错}
复制代码

2、子类不是泛型类

子类不是泛型类,父类要明确泛型的数据类型

class Test<T>{    private T a;    public T getA(T b){        return a;    }}
class Son1 extends Test<String>{ //子类不是泛型类,父类要明确泛型的数据类型}class Son2 extends Test<T>{ //报错:需要明确父类的泛型数据类型}
复制代码

泛型接口

泛型接口的定义语法


interface Test<T>{    T get(T a);}class Son1<T,K> implements  Test<T>{    @Override    public T get(T a) {        return null;    }}class Son2 implements Test<String>{    @Override    public String get(String a) {        return null;    }}class Son3 implements Test{//如果不写的话,默认的T就会变成Object    @Override    public Object get(Object a) {        return null;    }}
复制代码
  1. 实现类不是泛型类,接口要明确数据类型

  2. 实现类也是泛型类,实现类和接口的泛型类型要一致

泛型方法

  • pub1ic 与返回值中间非常重要,可以理解为声明此方法为泛型方法。

  • 只有声明了的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。

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

  • 与泛型类的定义一样,此处 T 可以随便写为任意标识,常见的如 T、E、K、V 等形式的参数常用于表示泛型。

  • 反向方法支持静态,但是泛型类中的成员方法不支持静态 static 的使用

举例如下:

class Test1{    public <T> T geta(T a){        return a;    }}public class Main {    public static void main(String[] args) {        Test1 test1 = new Test1();        Integer geta = test1.geta(1);//根据传入参数的类型指定泛型形参  }}
复制代码

反向方法的可变参数

泛型方法总结:

  • 泛型方法能使方法独立于类而产生变化

  • 如果 static 方法要使用泛型能力,就必须使其成为泛型方法

类型通配符

类型通配符上限

类型通配符一般是使用?代替具体的类型参数,所以类型通配符是类型实参.「? extends Number」,表示的是类型通配符的上线是 Number

class Test1<T>{    public void  get1(){    }}public class Main{    public static void main(String[] args) {        get(new Test1<>());        get1(new Test1<Integer>());    }
    public static void get(Test1<?> test1){        test1.get1();    }    public static void get1(Test1<? extends Number> test1){        test1.get1();    }}
复制代码

类型通配符下限

采用 super 关键字 「? super Number」表示类型最低是 Number

class Test1<T>{    public void  get1(){    }}public class Main{    public static void main(String[] args) {        get(new Test1<>());        get1(new Test1<Number>());    }
    public static void get(Test1<?> test1){        test1.get1();    }    public static void get1(Test1<? super Number> test1){        test1.get1();    }
复制代码

类型擦除

无限制的类型擦除

有限制的类型擦除

擦除方法中类型定义的参数

「桥接方法」因为在编译的时候,为了保证实现类重写了接口的方法,虽然实现类有了 Integer 的方法,但是在泛型擦除的时候会在实现类中生成一个 Object 的方法。


泛型与数组

泛型数组的创建

  • 可以声明带泛型的数组引用,但是不能直接创建带泛型的数组对象

  • 可以通过 java.lang.reflect.Array 的 newInstance(Class,int)创建 T[]数组

  1. 方法一

    public static void main(String[] args) {        ArrayList<String>[] a = new ArrayList<String>[4]; //错误案例        ArrayList<String>[] b = new ArrayList[4];//创建数组    }
复制代码
  1. 方法二

class Test1<T>{    private T[] arr;    public Test1(Class<T> clz,int len){ //创建数组        arr = (T[]) Array.newInstance(clz,len);    }    public void put(int index, T item){        arr[index]=item;    }}
复制代码

泛型与反射

    public static void main(String[] args) throws Exception {        Class test1Class= Test1.class;        Constructor constructor = test1Class.getConstructor();        Object o = constructor.newInstance();    }
复制代码

反射常用的泛型类

Class<T>Constructor<T>
复制代码


发布于: 刚刚阅读数: 3
用户头像

知识浅谈

关注

公众号:知识浅谈 2022.06.22 加入

乐于分享共同成长,学习何不带我一起.

评论

发布
暂无评论
由点到面贯穿整个Java泛型理解_Java泛型_知识浅谈_InfoQ写作社区