java 深入理解泛型

时间:2022-09-04 19:26:02

泛型相信很多人都遇到过,比如使用集合的时候类似List,封装适配器的时候。泛型在处理数据的时候可以帮助我们,只处理指定类型的数据,比如集合无论我们存什么样的数据,取出的时候都会被认为是Object的对象,一般都需要我们去强转为想要的数据类型,这个时候可能会出现类型转换错误。比如:

List list=new ArrayList<>();
list.add("你好");
list.add(5);
for (Object object : list) {
String str=(String) object;
System.out.println(str);
}

这样在执行的时候就会出现Integer cannot be cast to String

如果我们指定了泛型,如下

List<String> list=new ArrayList<>();
list.add("你好");
//编译不通过
list.add(5);

我们指定集合泛型为String,实例化的时候不必重复指定,这个时候在添加Integer类型数据就不能通过了。

正如你所见,泛型的语法格式就是< E >,这里的E就是所谓的参数化类型(和方法的形参一样,不是真实存在的东西)

  • 自定义泛型类或者接口
public class Pet<T> {

public void eat(T t){
System.out.println("吃"+t);
}

}

调用:

Pet<String> pet=new Pet<>();
pet.eat("s");

这里在定义一个类的时候,使用了泛型

  • 从泛型类派生子类
    • 子类继承时的格式
//继承泛型类的时候,父类不能跟泛型
public class Dog extends Pet<T>{

}

正确的格式,父类后跟具体类型

//继承泛型类的时候,父类跟具体类型
public class Dog extends Pet<String>{

}

和调用方法不同的是,泛型类或者泛型接口,可以不传入形参:

//也可以什么都不写
public class Dog extends Pet{

}

接口也是同样的写法,不在赘述。

  • 并不存在泛型类
        List<String> listS=new ArrayList<String>();
List<Integer> listI=new ArrayList<Integer>();
if (listI.getClass()==listS.getClass()) {
System.out.println("true");
System.out.println(listI.getClass().getSimpleName());
System.out.println(listS.getClass().getSimpleName());
}else {
System.out.println("flase");
System.out.println(listI.getClass().getSimpleName());
System.out.println(listS.getClass().getSimpleName());
}

运行结果:

true
ArrayList
ArrayList

也就是说,不管我们为泛型参数传入哪一种类型实参,对于java来说,它们依然被当做一个类来处理,在内存中也只占用一块内存空间,因此在静态方法,静态代码块或者静态变量的声明和初始化中不允许使用泛型,如下:

public class Pet<T> {
//代码不能通过,不能在声明静态变量时使用泛型
static T info;
//可以声明
T info2;

public void eat(T t){}
//下面代码错误,静态方法中不能使用泛型
public static void play(T t){
//下面代码错误
T a;
}
}

由于系统并不会产生真正的泛型类,所有instanceof关键字后不能有泛型类,如下:

        List<String> listS=new ArrayList<String>();
//编译错误,instanceof关键字后不能有泛型类
if(listS instanceof ArrayList<String>){}

泛型作为类型参数,可以让我们处理不同的指定类型的数据,但是泛型类、泛型接口是不存在的。