今天学习泛型的相关知识。
- 为什么用泛型
- 什么是泛型
- 泛型类
- 从泛型类派生子类
- 泛型接口
- 通配符,上边界,下边界
- 类型擦除
为什么用泛型
在使用Object类时,Object可以接收任意的对象类型,但是在实际的使用中,会有类型转换的问题,所以Java提供了泛型来解决这 个安全问题。
什么是泛型
泛型,在集合中,可以存放不同类型的数据(object类),但在后期对数据使用时会有数据类型转换的问题,所有最好只存一种类型,这时候可以使用泛型来解决这一问题,参数化类型,就是将类型由原来的具体的类型参数化,类似于方法中的 变量参数,此时类型也定义成参数形式,然后在使用/调用时传入具体的,类型泛型可以继承父类,也可以由接口定义。
例如:public class Demo<T> ,T为泛型的通配符号,还可以写为E、K、V。
泛型类
使用泛型定义于类中的类,统称为泛型类,通过泛型类可以完成对一组类的操作对外开放相同的接口。
import java.util.Arrays;
public class FXDemo13 <T> {
T number;
public FXDemo13(T number) {
this.number = number;
}
public T getNumber() {
return number;
}
public void setNumber(T number) {
this.number = number;
}
@Override
public String toString() {
return "FXDemo13{" +
"number=" + number +
'}';
}
public void show1(FXDemo13<? extends T> number) {
System.out.println(number);
}
public void show2(FXDemo13<? super T> number) {
System.out.println(number);
}
}
从泛型类派生子类
泛型可以派生出子类,当子类是泛型类时,子类和父类的类型要一致。
例如:class A<T> extends Demo<T>
但子类不是泛型类时,父类要明确泛型的数据类型。
例如:class A extends Demo<String>
public class FX2Demo13<T> extends FXDemo13 <T> {
public FX2Demo13(T number) {
super(number);
}
}
泛型接口
泛型接口和泛型类的定义基本一样,
public interface FX3Demo13 <T>{ }
当子类是泛型类时,子类和父类的类型要一致。
例如:class A<T> implements Demo<T>
但子类不是泛型类时,父类要明确泛型的数据类型。
例如:class A implements Demo<String>
泛型通配符,上边界,下边界
类型通配符一般是使用"?"代替具体的类型实参。
类型通配符上限
类
/
接口
<
?
extends
实参类型
>
要求该泛型的类型,只能是实参类型,或实参类型的子类类型。
类型通配符下限
类
/
接口
<
?
super
实参类型
>
要求该泛型的类型,只能是实参类型,或实参类型的父类类型。
//? 表示实际传入的参数的泛型类型 ?表示可以是任意的 也称无界通配符
public void show(Demo16<?>obj) {
}
//类型通配符上限:实际传入的类型,只能是T(Number) 获者T的子类
public void show1(Demo16<? extends T>obj) {
}
//类型通配符下限:实际传入的类型,只能是T(Number) 获者T的父类
public void show2(Demo16<? super T>obj) {
}
类型擦除
泛型信息只存在编译阶段,在进入JVM之前,与泛型相关的信息会被擦除。通俗来讲,泛型类和普通类在java虚拟机内没有什么特别的地方。
import java.lang.reflect.Field;
public class Demo15 {
public static void main(String[] args) throws NoSuchFieldException {
FXDemo13<Integer> f1=new FXDemo13<>(23);
Class c = f1.getClass();
Field field = c.getDeclaredField("num");
field.setAccessible(true);
System.out.println(field.getType());
}
}