泛型机制将类型转换时的类型检查从运行时提前到了编译时,使用泛型编写的代码比杂乱的使用object并在需要时再强制类型转换的机制具有更好的可读性和安全性。
泛型程序设计意味着程序可以被不同类型的对象重用,类似c++的模版。
泛 型对于集合类尤其有用,如ArrayList。这里可能有疑问,既然泛型为了适应不同的对象,ArrayList本来就可以操作不同类型的对象呀?那是因 为没有泛型之前采用继承机制实现的,实际上它只维护了一个Object对象的数组。结果就是对List来说它只操作了一类对象Object,而在用户看来 却可以保存不同的对象。
泛型提供了更好的解决办法——类型参数,如:
2.类型检查,避免插入非法类型。
3. 获取数据时不在需要强制类型转换。
使用时:Pair<String> p = new Pair<String>();
此时类内部的field1就是字符串类型了。
如果引用多个类型,可以使用逗号分隔:<S, D>
类型参数名可以使用任意字符串,建议使用有代表意义的单个字符,以便于和普通类型名区分,如:T代表type,有原数据和目的数据就用S,D,子元素类型用E等。当然,你也可以定义为XYZ,甚至xyZ。
泛型方法有自己的类型参数,泛型类的成员方法使用的是当前类的类型参数。
方法中有<T> 是泛型方法;没有的,称为泛型类中的成员方法。
为什么是extends不是 implements,或者其他限定符?
其次,T既可以是类对象也可以是接口,如果是类对象应该是`implements`,而如果是接口,则应该是`extends`;从子类型上来讲,extends更接近要表达的意思。
好吧,这是一个约定。
泛型限定的优点:
限制某些类型的子类型可以传入,在一定程度上保证类型安全;
可以使用限定类型的方法。如:
我们知道final类不可继承,在继承机制上class SomeString extends String是错误的,但泛型限定符使用时是可以的:<T extends String>,只是会给一个警告。
后面的通配符限定有一个super关键字,这里没有。
这就是擦除的残留。反汇编:
descriptor:对方法参数和返回值进行描述; signature:泛型类中独有的标记,普通类中没有,JDK5才加入,标记了定义时的成员签名,包括定义时的泛型参数列表,参数类型,返回值等;
可以看到public T field1;是签名,还保留了定义的格式;其对应的参数类型是Ljava/lang/Object;。
最后一行是类的签名,可以看到T后面有跟了擦除后的参数类型:<T:Ljava/lang/Object;>。
这样的机制,对于分析字节码是有意义的。
byte,char,short,int,long,float,double,boolean
从包装类角度来看,或者说三个: Number(byte,short,int,long,float,double),char,boolean
注,可以创建通配类型数组,然后进行强制类型转换。不过这是类型不安全的。
有一个特例是方法的可变参数,虽然本质上是数组,却可以使用泛型。
安全的方法是使用List。
2. 静态的泛型方法,是在方法层面定义的,就是说在调用方法时,T所指的具体类型已经明确了。
换一个角度来考虑,定义Son时,Parent已经明确了类型参数为String,那么再写setName(Stirng)是重写,也是合理的。
我非要重载怎么办?只能曲线救国,改个名字吧。
泛型有一个原则:一个类或类型变量不可成为两个不同参数化的接口类型的子类型。如:
这称为子类型限定通配符,又称上边界通配符(upper bound wildcard Generics),代表继承它的所有子类型,通配符匹配的类型不允许作为参数传入,只能作为返回值。
2. 都可以传入Integer或Integer的子类型。
2. 但是由于Java的所有对象的顶级祖先类都是Object,因此可以用Object获取getName返回值。
因此,无限定通配符可以作为返回值,不可做入参。
返回值只能保存在Object中。
P<?> 和P
Pair可以调用setter方法,这是它和Pair<?>最重要的区别。
P<?> 不等于 P<Object>
P<Object>是P<?>的子类。
2. 子类型通配符:set方法受限,只可读,不可写;
3. 超类型通配符:get方法受限,不可读(Object除外),只可写;
4. 无限定通配符,只可读不可写;
5. 如果你既想存,又想取,那就别用通配符;
6. 不可同时声明子类型和超类型限定符,及extends和super只能出现一个。
注:
只允许捕获单个、确定的类型,如:ArrayList<Pair<?>> 是无法使用 ArrayList<Pair<T>> 捕获的。
例如:有一个泛型类Parent<T>,那么Son类定义时有两种方式初始化父类型的类型参数:
1 用具体类型初始化:
无论P和S有什么继承关系,一般Pair<P>和Pair<S>没什么关系。
泛型类自身可以继承其他类或实现接口,如 List<T>实现ArrayList<T>
泛型类可以扩展泛型类或接口,如ArrayList<T> 实现了 List<T>,此时ArrayList<T>可以转换为List<T>。这是安全的。
Parent<T>和Parent
Parent<T>随时都可以转换为原生类型Parent,但需要注意类型检查的安全性。
Person<? extends XXX>
严格讲通配符限定的泛型对象不属于继承范畴,但使用中有类似继承的行为。
Son是Parent的子类型,那么Person<? extends Son>就是Person<? extends Parent> 的子类型。
Person<? extends Object> 等同于 Person<?>,那么基于上以规则可以推断:Person<? extends Parent> 是 Person<?> 的子类型。
Person<Object> 是 Person<?> 的子类型。
User.java
从这一机制,可以通过AbstractBaseDaoImpl实现通用的JDBA DAO。
完善AbstractBaseDaoImpl.java