Java的自限定泛型
一、古怪的循环
古怪的循环泛型(CRG):类相当古怪地出现在出现在它的基类中。
我创建一个新类,它继承自一个泛型类型,这个泛型类型接受我的类的名字作为其参数。
class GenericType<T>{}
// 古怪的循环: 类相当古怪地出现在它自己地基类中
public class CuriouslyRecurringGeneric extends GenericType<CuriouslyRecurringGeneric>{
Java的泛型关乎参数和返回类型,因此它能够产生使用导出类作为其参数和返回类型的基类,它还能将导出类型作为其域类型。
CRG的本质:基类用导出类代替其参数。
这意味着泛型基类变成了一种其所有导出类的公共功能的模版,但是这些功能对于其所有参数和返回值,将使用导出类型。也就是说,在所产生的类中使用确切类型而不是基类型。
public class BasicHolder<T> {
T element;
void set(T arg){element = arg;}
T get(){return element;}
void f(){
System.out.println(element.getClass().getSimpleName());
}
}
//
class Subtype extends BasicHolder<Subtype>{}
public class CRGWithBasicHolder {
public static void main(String[] args) {
Subtype st1 = new Subtype(), st2 = new Subtype();
st1.set(st2);
Subtype st3 = st1.get();
st1.f();
}
}
上面代码中BasicHolder
可以使用任何类型作为其泛型参数,就像下面:
class Other{}
class BasicOther extends BasicHolder<Other>{}
为了强制要求将正在定义的类作为参数传递给基类,需要使用自限定
二、自限定
自限定:class SelfBounded<T extendsSelfBounded>
, 可以保证类型参数必须与正在定义的类相同。
自限定只能强制作用于继承关系。
class SelfBounded<T extends SelfBounded<T>>{
T element;
SelfBounded<T> set(T arg){
element = arg;
return this;
}
T get(){return element;}
}
class A extends SelfBounded<A>{}
class A extends SelfBounded<A>{}
class B extends SelfBounded<A>{}
class C extends SelfBounded<C>{}
class D {}
/** 下面这种会报编译错误 */
//class E extends SelfBounded<D>{}
class F extends SelfBounded{}
三、自限定类型的价值——产生协变参数类型
3.1 协变返回类型
class Base{}
class Derived extends Base{}
interface OrdinaryGetter{
Base get();
}
interface DerivedGetter extends OrdinaryGetter{
// 覆盖的方法允许返回类型不同
@Override
Derived get();
}
public class CovariantReturnTypes {
void test(DerivedGetter d){
Derived d2 = d.get();
}
}
3.2 自限定泛型事实上将产生确切的导出类型作为其返回值
协变参数类型——方法参数类型会随着自类而变化,自限定类型还可以产生于子类类型相同的返回类型。
在非泛型代码中,参数类型不能随子类型发生变化。
class OrdinarySetter{
void set(Base base){
System.out.println("OrdinarySetter.set(base)");
}
}
class DerivedSetter extends OrdinarySetter{
void set(Derived derived){
System.out.println("DerivedSetter.set(derived)");
}
}
public class OrdinaryArguments {
public static void main(String[] args) {
Base base = new Base();
Derived derived = new Derived();
DerivedSetter ds = new DerivedSetter();
ds.set(derived);
ds.set(base);
}
}
/*
DerivedSetter.set(derived)
OrdinarySetter.set(base)
*/
上面set(derived)
和set(base)
都是合法的,因此DerivedSetter.set()
没有覆盖OrdinarySetter.set()
,而是重载了这个方法。
但是,在使用自限定类型时,在导出类中只有一个方法,并且这个方法接受导出类型而不是基类型作为参数。
interface SelfBoundingSetter<T extends SelfBoundingSetter<T>>{
void set(T arg);
}
interface Setter extends SelfBoundingSetter<Setter>{}
public class SelfBoundingAndCovariantArguments {
void testA(Setter s1, Setter s2, SelfBoundingSetter sbs){
s1.set(s2);
/**
* 下面这个调用会报编译错误
* 编译期不能识别将基类当作参数传递给set()的尝试,因为没有任何方法具有这样的签名
* 实际上,这个参数已经被覆盖
* */
// s1.set(sbs);
}
}
如果不使用自限定类型,普通的继承机制就会介入,而你能够重载,就像在非泛型的情况下一样:
class GenericSetter<T> {
void set(T arg){
System.out.println("GenericSetter.set(base)");
}
}
class DerivedGS extends GenericSetter<Base>{
void set(Derived derived){
System.out.println("DerivedGS.set()");
}
}
public class PlainGenericInheritance{
public static void main(String[] args) {
Base base = new Base();
Derived derived = new Derived();
DerivedGS derivedGS = new DerivedGS();
derivedGS.set(derived);
derivedGS.set(base);
}
}