泛型类
从JDK1.5以后引入了三大常用新特性:泛型、枚举(enum)、注解(Annotation)。其中在JDK1.5中泛型是一件非
常重要的实现技术,它可以帮助我们解决程序的参数转换问题。
范例:泛型类的基本语法
class MyClass<T> {
T value1;
}
使用泛型类
MyClass<String> myClass1 = new MyClass<String>();
MyClass<Integer> myClass2 = new MyClass<Integer>();
注意:泛型只能接受类,所有的基本数据类型必须使用包装类!这里需要注意的是,泛型类可以接收多个类型参数。
class MyClass<T,E>
泛型方法
泛型不仅可以用于定义类,还可以单独来定义方法。如下所示:
class MyClass {
public <T> void testMethod(T t) {
System.out.println(t);
}
}
泛型方法与泛型类稍有不同的地方是,类型参数也就是尖括号那一部分是写在返回值前面的。 <T> 中的 T 被称为类型参数,而方法中的 T 被称为参数化类型,它不是运行时真正的参数。
泛型方法与泛型类可以共存,如下所示:
范例:泛型方法与泛型类共存
class MyClass<T>{
public void testMethod1(T t) {
System.out.println(t);
}
public <T> T testMethod2(T t) {
return t;
}
}
public class Test {
public static void main(String[] args) {
MyClass<String> myClass = new MyClass<>();
myClass.testMethod1("hello 泛型类");
Integer i = myClass.testMethod2(100);
System.out.println(i);
}
}
上面代码中,MyClass <T> 是泛型类,testMethod1 是泛型类中的普通方法,而 testMethod2 是一个泛型方法。而泛型类中的类型参数与泛型方法中的类型参数是没有相应的联系的,泛型方法始终以自己定义的类型参数为准。
泛型类的实际类型参数是 String,而传递给泛型方法的类型参数是 Integer,两者不相干。
但是,为了避免混淆,如果在一个泛型类中存在泛型方法,那么两者的类型参数最好不要同名。
通配符(重点)
在程序类中追加了泛型的定义后,避免了ClassCastException的问题,但是又会产生新的情况:参数的统一问题。
范例:使用通配符
void fun(Message<?> temp)
在"?"的基础上又产生了两个子通配符:1) ? extends 类:设置泛型上限:
例如:? extends Number,表示只能够设置Number或其子类,例如:Integer、Double等;
2) ? super 类:设置泛型下限:
例如:? super String,表示只能够设置String及其父类Object。
泛型接口
泛型除了可以定义在类中,也可以定义在接口里面,这种情况我们称之为泛型接口。范例:定义一个泛型接口
interface IMessage<T> { // 在接口上定义了泛型
public void print(T t) ;
}
对于这个接口的实现子类有两种做法:
// 范例:在子类定义时继续使用泛型
interface IMessage<T> { // 在接口上定义了泛型
public void print(T t);
}
class MessageImpl<T> implements IMessage<T> {
@Override
public void print(T t) {
System.out.println(t);
}
}
public class TestDemo {
public static void main(String[] args) {
IMessage<String> msg = new MessageImpl();
msg.print("Hello World");
}
}
// 范例:在子类实现接口的时候明确给出具体类型
interface IMessage<T> { // 在接口上定义了泛型
public void print(T t);
}
class MessageImpl implements IMessage<String> {
@Override
public void print(String t) {
System.out.println(t);
}
}
public class TestDemo {
public static void main(String[] args) {
IMessage<String> msg = new MessageImpl();
msg.print("Hello World");
}
}
类型擦除
泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。
class MyClass<T> {
private T message;
public T getMessage() {
return message;
}
public void setMessage(T message) {
this.message = message;
}
public void testMethod1(T t) {
System.out.println(t);
}
}
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());
}
}
打印的结果为 true 是因为 MyClass<String> 和 MyClass<Integer> 在 jvm 中的 Class 都是 MyClass.class。
在泛型类被类型擦除的时候,之前泛型类中的类型参数部分如果没有指定上限,如 <T> 则会被转译成普通的Object 类型,如果指定了上限如 <T extends String> 则类型参数就被替换成类型上限。