一.定义泛型接口,类
泛型的实质:允许在定义接口,类,方法时声明类型形参,这个类型形参将在声明变量,创建对象,调用方法时动态的指定,几乎所有可使用普通类型的地方都都可以使用这种类型形参。
例如 Java5改写后的List接口:
<span style="font-size:18px;"><span style="font-size:18px;">public interface List<E>{//定义接口时指定了一个类型形参,名为E
void add(E x);
Iterator<E> iterator();
...
}</span></span>
如果为E传入String类型实参,则产生了一个新类型:List<String>类型,可以认为List<String>是List的子接口。
我们可以为任何类,接口添加泛型声明,,例如Apple类:
<span style="font-size:18px;">package genericity;
import structurerOverride.Apple;
public class Applee<T> {
private T info;
public T getInfo() {
return info;
}
public void setInfo(T info) {
this.info = info;
}
public Applee() {}
public Applee(T info){
this.info=info;
}
public static void main(String[] args) {
//由于传给T形参的是String,所以构造器参数只能是String
Applee<String> a1=new Applee<>("苹果");
System.out.println(a1.getInfo());
//由于传给T形参的是Double,所以构造器参数只能是Double
Applee<Double> a2=new Applee<>(2.5);
System.out.println(a2.getInfo());
}
}
</span>
这样在使用Apple<T>时就可以为T类型传入多个类型,生成形如Apple<String>,Apple<Double>...的多个逻辑子类
(虽然并没有什么实际意义)
二.从泛型类派生子类
当使用接口,父类时不能再包含类型形参 例如下面的代码是错误的
<span style="font-size:18px;"><span style="font-size:18px;">public class A extendds Aapple<T>{ }</span></span>
如果想从Apple类派生一个子类,可以改为如下代码:
<span style="font-size:18px;"><span style="font-size:18px;">public class A extendds Aapple<String>{ }</span></span>
此时Apple类中所有使用T类型的地方都将被替换成String类型三.实际上并不存在泛型类,我们只是逻辑上这么称呼
例如:
List<String> l1=new ArrayList<>();
List<Integer> l2=new ArrayList<>();
System.out.println(l1.getClass()==l2.getClass());
可能有读者认为会输出false,但实际上输出true,因为不管泛型的实际类型是什么,它们在运行时总有同样的类
不管为泛型的类型形参传入哪一种类型实参,对于Java来说,它们依然被当成同一个类处理,在内存中也只占用一块内存空间,因此在静态方法,静态初始化块或静态变量的声明和初始化时不允许使用类型形参。
类型通配符将在下一篇记下