版权声明:转载原创博客请附上原文链接 https://blog.csdn.net/weixin_43495590/article/details/89181831
一:概述
Java是一种强类型语言,泛型概念的设计可以说是对类型使用的放松,对类型检测的加强。特别是常用集合中泛型嵌入结局了类型强转随时会发生的ClassCastException,同时也显著提升代码可读性
一:泛型类
类名后
定义泛型,使用格式。中的大写字母知识示例,JDK中常用T、E、K、V等- 具体类型使用时使用<具体类型>格式声明即可
- 多个泛型使用
逗号隔开
即可
public class GenericTest<T,R>{
public R testMethod(T t,R r){
return r;
}
}
二:泛型方法
- 方法泛型声明在
修饰符之后,返回值之前
,格式与泛型类一致 - 泛型方法要求必须声明自己的泛型,使用泛型类泛型不能称之为泛型方法
- 如示例所示,泛型方法声明使用与泛型类同一字母,但是这两个泛型可以使用不同实际类型
- 泛型方法实际类型在调用方法名字之前确定,可以省略
静态方法不能使用类泛型
,因为静态方法加载时类泛型还并未确认
public class GenericTest<T,R>{
// 不是泛型方法
public R testMethod(T t,R r){
return r;
}
public <T> T genericMethod(T t){
return t;
}
public static void main(String[] args) {
GenericTest<String,Integer> gt = new GenericTest<>();
Character c = null;
gt.<String>genericMethod("");
}
}
四:泛型接口
- 泛型接口声明与泛型类声明保持一致
泛型接口被实现的时候可以继续保持泛型即实现类与接口后都需要继续跟泛型
,不需要保持可以直接在接口名后声明实际类型
public interface GenericInterface<E> {
void testMethod(E e);
}
public class GenericTest<E> implements GenericInterface<E>{
@Override
public void testMethod(E e) {}
}
class GenericClass implements GenericInterface<String>{
@Override
public void testMethod(String s) {}
}
五:无限定通配符与限定
假定People是Student的父类,有一个方法要求传入参数ArrayList,声明一个ArrayList属性传参调用该方法,能通过编译么?牢记一点,ArrayList<Student>并不是ArrayList<People>的子类
test
(java.util.ArrayList<com.zsl.People>)
in GenericTest cannot be applied
to
(java.util.ArrayList<com.zsl.Student>)
public class GenericTest{
public void test(ArrayList<People> arr){}
public static void main(String[] args) {
ArrayList<Student> arr = new ArrayList<>();
new GenericTest().test(arr); // 不能通过编译
}
}
class People{}
class Student extends People{}
上述问题表达了固定泛型使用的不方便,这时候通配符"?"应运而生,表示任意类型,修改代码如下
public void test(ArrayList<?> arr){}
编译可以正常通过了,但问题是这样操作导致ArrayList里的元素不能调用People方法,也就是泛型擦除后只能是Object。这时候就可以考虑泛型的上下边界即限定符使用
class People{
public void mm(){}
}
public void test(ArrayList<? extends People> arr){
arr.forEach(s -> s.mm());
}
extends限定泛型上界,super限定泛型下界。extends在泛型擦除后的类型为上界,多个上界取最左
// 泛型擦除后类型为People
// 一般让没有具体方法的限定放右边
<T extends People & Comparable>
目光回到ArrayList<? extends People>这里,当出现这样的限定后集合的add()将失效,因为People的派生类可以有很多,JVM并不确定是哪个,所有的添加都无法通过编译
public void test(ArrayList<? extends People> arrayList){
arrayList.add(new People()); // 不能编译
arrayList.add(new Student()); // 不能编译
}
有个PECS原则,Producer Extends Consumer Super。生产意味着频繁被读取适合使用上界extends,消费意味需要随时补充适合使用下界super
六:注意事项
6.1 泛型不能定义为基本类型
意思就是泛型的实际类型不能是基本类型,泛型擦除后若未定义上界都会使用Object代替,但是基本类型并不是Object子类所以不能使用