泛型相信很多人都遇到过,比如使用集合的时候类似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>){}
泛型作为类型参数,可以让我们处理不同的指定类型的数据,但是泛型类、泛型接口是不存在的。