一.概念
1.“宽泛的数据类型”,就是将类型由原来的具体的类型泛化。
泛型建立对象时不指定类中属性的具体类型,而是在声明及实例化对象时由外部指定。泛型可以提高数据安全性。
2.作用:提高安全性;避免强转。
二.泛型的简单使用
1.泛型类:可以看做是普通类的工厂
使用要点:
①类型参数(比如这里的T)可以随便写为任意标识,常见的有T,K,E,V等;
②在实例化泛型类时,必须指定T的具体类型,指定的类型参数只能是类类型,不能是基本类型
③构造函数中可以省略类型参数,省略的类型参数可以从指定的具体类型参数中推断得出
/**
* @Author DreamYee
* @Create 2020/02/23 15:10
*/
public class 泛型class<T> {
private T apple;
private T pear;
public 泛型class(){
apple=null;
pear=null;
}
public 泛型class(T apple,T pear){
this.apple=apple;
this.pear=pear;
}
public T getApple(){
return apple;
}
public void setApple(T apple) {
this.apple = apple;
}
public T getPear(){
return pear;
}
public void setPear(T pear) {
this.pear = pear;
}
public static void main(String[] args) {
泛型class<String> aClass=new 泛型class<>("我是苹果","我是梨");
System.out.println(aClass.getApple());
System.out.println(aClass.getPear());
}
}
2.泛型方法
使用要点:
①public与返回值中间非常重要,可以理解为声明此方法为泛型方法。
②只有声明了的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法,表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。
③静态方法与泛型 — 静态方法无法访问类型定义的泛型,即无法使用定义泛型类时的类型参数,需要重新再静态泛型方法上声明。
/**
* @Author DreamYee
* @Create 2020/02/23 15:53
*/
public class method2 {
public static <T> String By(T bus,T taxi){
String gongju="aaa";
if(gongju!=bus){
return gongju;
}else {
return "啊啊啊";
}
}
public static void main(String[] args) {
String by=By("aaa","bbb");
System.out.println(by);
}
}
3.通配符问题
<?>用于承接不同类型的泛型对象。
<? extends T>:是 “上界通配符(Upper Bounds Wildcards)”,泛型只能是T的子类/本身;
<? super T>:是 “下界通配符(Lower Bounds Wildcards)”,泛型只能是T的父类/本身;
(1)上限
为泛型添加上边界,即传入的类型实参必须是指定类型或指定类型的子类。使用extends指定上限通配符。
问:为什么使用extends?而不用implements?
答:限定类可以是类,也可以是接口,选择extends的原因是更接近子类的概念。
(2)下限
下限通配符使用super关键字实现。
一个类型变量或通配符可以有多个限定。
限定类型间用&分割开,逗号用来分割类型变量。
Java的继承中,可以根据需要拥有多个接口的超类型,但限定中最多只有一个类,且必须放到第一位。
import java.util.ArrayList;
import java.util.List;
/**
* @Author DreamYee
* @Create 2020/02/23 16:57
*/
public class 上限 {
public static void main(String[] args) {
ArrayList<Apple> p1=new ArrayList<Apple>();
ArrayList<? extends Apple> p3=new ArrayList<Apple>();
p3=new ArrayList<RedApple>();
if(p3.size()!=0){
Apple apple=p3.get(0);
}
ArrayList<? super Apple> p4=new ArrayList<Apple>();
p4=new ArrayList<Fruit>();
p4=new ArrayList<Apple>();
p4.add(new RedApple());
Object o=p4.get(0);
System.out.println(o);
List<Apple> p2=new ArrayList<>();
}
}
class Fruit{
}
class Apple extends Fruit{
}
class RedApple extends Apple{
}
(3)类型擦除
Java 的泛型只在编译阶段有效,编译过程中正确检验泛型结果后,会将泛型相关信息擦除,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法,即泛型信息不回进入运行时阶段,无论何时定义一个泛型类型,都自动提供一个相应的原始类型,原始类型的名字就是删除类型参数后的泛型类型名,擦除类型变量,并且替换为限定类型(无限定的变量用Object),有多个限定的,就使用第一个限定类型。