一、通配符
在程序类中追加了泛型的定义后,避免了ClassCastException的问题,但是又会产生新的情况:参数的统一问题。
观察这样一个例子
class Message<T> {
private T message ;
public T getMessage() {
return message;
}
public void setMessage(T message) {
this.message = message;
}
}
public class Test {
public static void main(String[] args) {
Message<String> message = new Message<>() ;
message.setMessage("Hello");
fun(message);
}
public static void fun(Message<String> temp){
System.out.println(temp.getMessage());
}
}
如果我们将泛型类型设置为Integer,那么fun方法就会产生错误,因为fun方法只能接收String类型。
对于这个fun方法,我们需要让他接收所以的泛型类型,但又不能让用户随意修改,这种情况下我们可以使用通配符来解决。
1.“?”通配符——作用于方法参数声明
public static void fun(Message<?> temp){
System.out.println(temp.getMessage());
}
此时方法参数表示可以接收任意类型的Myclass对象
由于无法确定入参的类型,因此“?”通配符下的泛型参数,只能取得类中属性值,无法进行属性值的设置。
即不能写 temp.setMessage(222);
在“?”的基础上,又产生了2个子通配符
- ? extends 类:设置泛型上限
- ? super 类:设置泛型下限
2.设置泛型上限-用于泛型类的声明,也可以用于方法参数
泛型类声明:T extends 类
class myClass<T extends Number>{
表示T这个类型只能是Number类或Number类的子类。
}
方法参数:?extends 类
public static void fun(Message<? extends Number> temp){
表示方法入参只能接收Number以及其子类对象,例如:Integer、Double等;
}
方法参数设置泛型上限仍然只能取得类中属性值,而无法设置值,也是因为无法确定类型,我们只知道父类,但父类不一定能发生向下转型变为子类。
3.设置泛型下限-只能用于方法参数
? super 类
public static void fun(Message<? super String> temp){
表示方法入参只能接收此类以及其父类对象
}
方法参数设置泛型下限不仅可以取得类中属性值,还可以设置属性值。因为子类可以天然向上转型变为父类。
注意:上限可以用在声明,不能修改;而下限只能用在方法参数,可以修改内容!
二、类型擦除
泛型是 JDK1.5 版本才引进的概念,在这之前是没有泛型的概念的,但显然,泛型代码能够很好地和之前版本的代码很好地兼容。这是因为,泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。
换句话说,泛型类与普通类在JVM中没有任何区别
泛型类进入JVM之前会进行类型擦除,泛型类的类型参数如果没有指定类型上限,则擦除成为Object类;如果类型参数指定类型上限,擦除为相应的类型上限。例如:
<T> 擦除成为 Object类型
<T extends String> 擦除成为 String类型