看这一章花了好些时间,直到现在依然有一些不明朗的地方。如果有个人认识不正确的地方,烦请指出。
1.
引用
有许多原因促成了泛型的出现,而最引人注目的一个原因,就是为了创造
容器类。
class Automobile {}
public class Holder1 {
private Automobile a;
public Holder1(Automobile a) {this.a = a;}
public void set(Automobile a) { this.a = a; }
public Automobile get() { return a; }
}
这个类持有一个Automobile类型的对象a,但重用性很差,如果要持有其他非Automobile类型需重写。
public class Holder2 {
private Object a;
public Holder2(Object a) { this.a = a; }
public void set(Object a) { this.a = a; }
public Object get() { return a; }
}
这个类持有Object类型的对象a,但可以往里随意set各种类型的对象。但我们只需要持有一种特定类型,并且想保证类型的正确性,所以请用泛型吧。
public class Holder3<T> {
private T a;
public Holder3(T a) { this.a = a; }
public void set(T a) { this.a = a; }
public T get() { return a; }
public static void main(String[] args) {
Holder3<Pet> h3 = new Holder3<Pet>(new Cat());
h3.set(new Dog());
Pet a = h3.get();
}
}
这个类持有的是T类型的对象a,当创建Holder3对象时,只需告诉编译器要使用Pet类型。并且当h3对象被创建出来,它就只能持有Pet类型或其子类型,如本例中的Cat和Dog,但你不能给它set People类型的对象,即编译器会做类型检查。
2.Java泛型局限之一,基本类型无法作为类型参数。但可以使用包装类型,与基本类型进行转换。
3.关于擦除:
引用
在泛型代码内部,无法获得任何有关泛型参数类型的信息
举个例子就是new ArrayList<String>().getClass()与new ArrayList<Integer>().getClass()所得到的是相同的实例。
引用
Java泛型是使用擦除来实现的,这意味着当你在使用泛型时,任何具体的类型信息都被擦除了,你唯一知道的就是你在使用一个对象。因此List<String>和List<Integer>在运行时事实上是相同的类型。这两种形式都被擦除成它们的“原生”类型,即List。
4.关于边界:
引用
边界使得你可以再用于泛型的参数类型上设置条件。
因为擦除了类型信息,所以类似List<T>这种无界泛型参数的写法实际运行时只认为参数是一个Object类型。设置泛型边界使用
extends关键字,如:class Colored<T extends HasColor>。
5.关于通配符“?”:
假设有如下的类继承关系:
class Fruit {}
class Apple extends Fruit {}
在泛型的使用中,却不能这样初始化:List<Fruit> list = new ArrayList<Apple>();
这里用个人做的练习28的代码来理解用法,注意里面关键字super和extends的使用:
class GenericSet<T> {
public void setMethod(T param) {
}
}
class GenericGet<T> {
private T param;
public T getMethod() {
return param;
}
}
public class Practise28 {
static <T> void setMethod(GenericSet<? super T> param, T item ) {
param.setMethod(item);
}
static <T> void getMethod(GenericGet<? extends T> param) {
param.getMethod();
}
public static void main(String[] args) {
GenericSet<Fruit> individual1 = new GenericSet<Fruit>();
GenericGet<Fruit> individual2 = new GenericGet<Fruit>();
setMethod(individual1, new Apple());
getMethod(individual2);
}
}
6.关于自限定类型:
使用个人做的练习34的代码来理解(不要吐槽命名。。。):
abstract class MyAbstract<T extends MyAbstract<T>>
{
abstract T method(T i);
T invoke(T i) {
System.out.println(i.getClass().getSimpleName());
return method(i);
}
}
public class Practise34 extends MyAbstract<Practise34> {
public static void main(String[] args) {
System.out.println(new Practise34().invoke(new Practise34()));
}
@Override
Practise34 method(Practise34 i) {
return i;
}
}