一、概念解释
泛型类:
- 引出:JDK1.5,为了解决程序中向下转型出现的参数转换安全问题
- 解释:类在定义的时候不会设置属性或方法参数的具体类型,而是使用时定义
- 基本语法:MyClass类就是一个泛型类
class MyClass<T>{ T value;//T代表变量类型,可以是任意类型,与<T>不同 }
<T>:T代表类型参数,可以指代任何引用类型(这里指的是Object类可以接收的类型)
-
常见参数类型:T(类)、E(元素)、K,V(键值对)
-
作用:
-
用于检测编译期,参数类型设置问题,只有传入参数与使用定义类型一致时才可设置
-
杜绝向下转型带来的隐患
二、泛型方法
- 语法
public <T> T test(T t){
return t;
}
- 第一个T:<T>,代表类型参数,不能省略,要写在第二个T之前
- 第二个T:代表方法的返回值类型
- 第三个T:代表方法参数的类型
- 与泛型类共存
- 若泛型类与泛型方法共存,使用同一个类型参数,泛型类T与泛型方法T没有任何联系,泛型方法始终以自己定义的类型参数为准
- 建议使用不同的标识
- 应用:
package generics;
//泛型
class Point<T>{
private T x;
private T y;
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
public T getY() {
return y;
}
public void setY(T y) {
this.y = y;
}
@Override
public String toString() {
return "Point [x=" + x + ", y=" + y + "]";
}
}
public class Test {
public static void main(String[] args) {
Point<String> point = new Point<String>();
point.setX("qwe");
point.setY("asd");
System.out.println(point);
Point<Integer> point2 = new Point<>();//1.7后new后可以不写类型
point2.setX(12);
point2.setY(23);
System.out.println(point2);
}
}
三、通配符
- 引出:解决参数统一问题,可以接收所有的泛型类型,又不能让用户(main)直接修改,使用通配符
- ?用于方法参数,指代任意类型
- eg:fun(MyClass<?> myclass) //表示可以接收任意类型的MyClass对象
- 由于类型无法确定,所以只能取得值,不能修改
- ?extend 类 :设置泛型上限,可用于类或方法参数
- eg:?extend Number:表示只能接收Number或其子类
- 用于方法参数时,只能取得值不能修改(类型无法确定)
- ?super 类 :设置泛型下限,只能用于方法参数
- ?super String :表示只能接收String或其父类(Object)
- 可以修改值,类型已确定,自己或父类,若此时?为父类,会默认发生向上转型
- 应用:
package generics;
//通配符
class MyClass<T>{
private T value;
public MyClass(T value) {
super();
this.value = value;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
public class Test1 {
public static void main(String[] args) {
// fun(new MyClass <Integer>(10));
fun(new MyClass <String>("qwe"));
MyClass<String> myClass = new MyClass<>("123");
MyClass<String> myClass1 = new MyClass<String>("123");
fun(myClass);
// fun(new MyClass <Double>(10.2));
fun(new MyClass<Object>("123"));
MyClass <Object> object = new MyClass<>("123");
fun(object);
}
// //所有类型
// public static void fun(MyClass<?> myClass) {
// System.out.println(myClass.getValue());//适用于所有类型
// }
// //Number或其子类
// public static void fun(MyClass<? extends Number> myClass) {
// System.out.println(myClass.getValue());//运行结果:10 10.2
// }
//String或其父类Object
public static void fun(MyClass<? super String> myClass) {
myClass.setValue("hello");
System.out.println(myClass.getValue());//运行结果:hello
}
}
四、泛型接口
- 定义:接口定义上使用此占位符<T>表示泛型接口
- 子类实现接口:
- 继续保留泛型:class MyClassImpl implements MyClass<T>
- 声明泛型类型:class MyClassImpl implements MyClass<String>
五、泛型擦除
- 解释:泛型是JDK1.5才引入的,而泛型能与之前的代码很好的兼容,这是因为泛型信息只存在于代码编译阶段,进入JVM之前,与泛型相关的信息会被擦除掉,这就是泛型擦除
- 所以,在JVM中泛型类与普通类没有任何区别
- 泛型、自动拆装箱、foreach都是Java中的语法糖(方便开发者使用,只存在于编译阶段,在运行阶段无用)
- 在泛型类被擦除时,之前泛型类中的参数如果没有指定上限,<T>会被转译为Object,若指定上限,<T>会被转译为类型上限