从Java 1.5 开始引入泛型的机制:泛型实现了参数化类型的概念,时代吗可以应用于多种类型。——————java编程思想
泛型的本质就是参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,
操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
个人理解:泛型更像是在编写代码阶段为了避免,因为类型不确定问题从而引发编译问题,对所使用的对象类型进行的限制;
特性
泛型只在编译阶段有效
本质上只存在于编译阶段,泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类
型擦除
就是说泛型是给程序员编写代码时看的,代码在进入JVM时,会将这些对象的类型同化
public class Test {
public static void main(String[] args) {
MyClass<String> myClass1 = new MyClass<>();
MyClass<Integer> myClass2 = new MyClass<>();
System.out.println(myClass1.getClass() == myClass2.getClass());
}
/*
ture
*/
}
证明MyClss在 jvm中对象是一个对象自动擦除泛型String和Integer 类型
泛型的字母
- 形式类型参数(formal type parameters)即泛型字母
- 命名泛型字母可以随意指定,尽量使用单个的大写字母(有时候多个泛型类型时会加上数字,比如T1,T2)
常见字母(见名知意)- T Type
- K V Key Value
- E Element
- 当类被使用时,会使用具体的实际类型参数(actual type argument)代替
泛型的使用
1)泛型类
只能用在成员变量上,只能使用引用类型
泛型类型用于类的定义中,被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口。最典型的就是各种容器类,如:List、Set、Map。
class MyClass<T> {
T value1;
}
有一个误区:泛型类的类型 在new对象的不一定传入实参,就是说不一定在<>填写参数,当不传入参数时,在使用泛型的时候如果传入泛型实参,则会根据传入的泛型实参做相应的限制,此时泛型才会起到本应起到的限制作用。如果不传入泛型类型实参的话,在泛型类中使用泛型的方法或成员变量定义的类型可以为任何的类型。
2)泛型接口
只能用在抽象方法上
//定义一个泛型接口
public interface Generator<T> {
public T next();
}
泛型接口的使用
class FruitGenerator<T> implements Generator<T>{
@Override
public T next() {
return null;
}
}
- 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中
即:class FruitGenerator implements Generator{ - 如果不声明泛型,如:class FruitGenerator implements Generator,编译器会报错:“Unknown class”
public class FruitGenerator implements Generator<String> {
private String[] fruits = new String[]{"Apple", "Banana", "Pear"};
@Override
public String next() {
Random rand = new Random();
return fruits[rand.nextInt(3)];
}
}
- 传入泛型实参时:
定义一个生产器实现这个接口,虽然我们只创建了一个泛型接口Generator - 但是我们可以为T传入无数个实参,形成无数种类型的Generator接口。
- 在实现类实现泛型接口时,如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型
即:Generator,public T next();中的的T都要替换成传入的String类型。
3)泛型方法
泛型方法:
- 泛型方法是独立定义(可以单独定义泛型方法),和类没有直接关系
- 泛型方法的类型参数是在方法返回值类型的前面定义 <T,…>
- 泛型方法的类型参数:方法之间没关系,和类也没关系
通配符
extends/super
-
上限(extends)
指定的类必须是继承某个类,或者实现了某个接口(不是implements),即<=? extends List
-
下限(super)即父类或本身
? super List
public class Demo{
public static vpid test(List<?> list){
List<?> list2;
list2 = new ArrayList<String>();
list2 = new ArratList<Integer>();
}
public static void main(String{} args){
test(new ArrayList<String>();
test(new ArrayList<Integer>();
}
}
总结
- 在实例化的时候,就必须声明泛型具体是一个什么类型。
- 使用泛型、通配符提高了代码的复用性。
- 把一个对象分为声明、使用两部分的话。泛型侧重于类型的声明上代码复用,通配符则侧重于使用上的代码复用。泛型用于定义内部数据类型的不确定性,通配符则用于定义使用的对象类型不确定性。
- 如果类型参数在方法声明中只出现一次,可以用通配符代替它。
- 不能同时声明泛型通配符上界和下界。
生命不息!!!奋斗不止!!!