p.s.这是萌新自己自学总结的笔记,如果想学习得更透彻的话还是请去看大佬的讲解
目录
- 泛型概念
- 泛型类
- 泛型接口
- 泛型接口的实现类
- 泛型方法
- 可变参数的泛型方法
- 泛型的通配符
泛型概念
泛型,顾名思义,广泛的类型,使用泛型可以帮助我们在一个特定的类、接口或集合、方法中操作不同数据类型的对象。我们可以指定集合中元素的数据类型,也可以使用泛型类来提高代码的复用性。
泛型是JDK5以后引入的特性,可以在编译阶段约束操作的数据类型,并进行检查
泛型的格式:<数据类型>。
注意:泛型只支持引用数据类型,如果想使用整数类型,那么需要使用其对应的包装类。
如果不使用泛型限制集合的数据类型的话,因为多态的弊端性我们将无法调用集合中元素的特有方法,如果强制转化就会出现下面这种情况
java"> ArrayList list = new ArrayList<>();list.add("a");list.add(12);list.add("c");//迭代器遍历Iterator it = list.iterator();while (it.hasNext()){//强制类型转换String str = (String) it.next();//多态的弊端是不能范文子类的特有方法//比如下面这种就会报错//str.length();System.out.println(str);}
如果没有泛型的时候,集合如何存储数据?
结论:如果我们没有给集合指定类型,默认认为所有的数据类型都是Object类型
此时可以往集合中添加任意的数据类型
但是有一个弊端:我们在获取数据的时候,无法使用其的特有行为
因此,在JDK5引入了泛型。泛型提供了编译时类型安全检测机制,该机制允许我们在编译时检测到非法的数据类型结构。其保证了类型安全,消除了强制类型的转换
泛型的本质就是参数化类型,也就是操作的数据类型被指定为一个参数
比如这种java">ArrayList<String> list = new ArrayList<>();
使用泛型限定后在添加的时候我们就只能添加String类型了,否则会报错
总结:泛型不仅可以用来统一数据类型,而且还把运行时期的问题提前到了编译期间,避免了强制转换可能出现的异常,因为在编译阶段就能确定下来
指定泛型的具体类型后,传递数据时,可以传入该类类型及其子类类型
如果不写泛型,类型默认是Object类型
泛型类
使用场景:当一个类中,某个变量的数据类型不确定的时候,就可以定义带有泛型的类
使用泛型类,我们可以创建具有相同属性、相同构造方法、相同方法的不同数据类型的对象
因此使用泛型类大大提高了代码的复用性
对象的数据类型则是在创建的时候才声明的
数据具备继承性,但是泛型不具备继承性,即泛型里面写的是什么类型,那么只能传递什么类型的数据
格式
java"> 修饰符 class 类名称<泛型标识,泛型标识···>{private 泛型标识 变量名;······
}
泛型标识可以理解为一种类型形参
常用的泛型标识有T、E、K、V等
java">package study.fanxing;public class Test<T> {private T key;public Test(T key) {this.key = key;}public T getKey() {return key;}public void setKey(T key) {this.key = key;}@Overridepublic String toString() {return "Test{" +"key=" + key +'}';}
}
可以看出泛型标识可以作为数据类、方法返回值、方法形参来使用
泛型接口
泛型接口的定义语法
java">interface 接口名称<泛型标识、泛型标识······> {泛型标识 方法名();······
}
泛型接口的实现类
若实现类不是泛型类,则接口要明确数据类型
若实现类也是泛型类,则实现类和接口的泛型标识要一致
java">public interface Generator<T> {
//泛型接口T getKey();
}//===========================================
class Apple<E,T> implements Generator<T>{private T key;private E value;public Apple(T key, E value) {this.key = key;this.value = value;}@Overridepublic T getKey() {return key;}public E getValue(){return value;}}
//===========================================
class Test2{public static void main(String[] args) {Apple<String,Integer> apple = new Apple<>(20,"aa");System.out.println(apple.getKey());System.out.println(apple.getValue());}
}
泛型方法
与泛型类类似,泛型方法是在调用方法的时候才声明了泛型的具体类型
下面这个不是泛型方法,只是一个数据类型为E的成员方法
java"> public E getValue(){return value;}
泛型方法的定义语法如下
java"> public <泛型标识、泛型标识······> 返回值类型 方法名(形参列表){方法体;}
注意事项
只有在修饰符和返回值类型之间有
<T、E······>
的方法才是泛型方法,泛型类中使用了泛型的成员方法(比如将泛型变量作为方法形参)并不是泛型方法
<T>
表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T
!泛型方法的数据类型和调用泛型方法的泛型类对象的数据类型没有关系!
如果类的成员方法使用了类的泛型,那么这个成员方法将不能用static修饰。但泛型方法可以用static修饰
将类定义为泛型则类的所有方法都可使用泛型,但将方法定义为泛型则只有该方法能使用泛型
可变参数的泛型方法
java">public static <E> void print(E... e){for (int i = 0; i < e.length; i++) {System.out.println(e[i]);}}
当不知道参数的个数时,这种在泛型后面加上...
的泛型方法称为可变参数的泛型方法,即它的参数可以改变
上面的代码为遍历一遍所有形参对应的实参对象
泛型的通配符
泛型的通配符:?
其不仅可以表示不确定的类型,还可以进行类型的限定
其限定方式有两种
<? extends E>
:表示可以传递E或E所有的子类类型(E要明确给出数据类型)
<? super E
>:表示可以传递E或E所有的父类类型(E要明确给出数据类型)
使用场景
如果我们在定义类、方法、接口的时候,如果类型不确定,就可以定义泛型类、泛型方法、泛型接口
如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以使用泛型的通配符
通配符使用的关键点:可以限定类型的范围