@lemonguge
2015-06-23T02:34:15.000000Z
字数 2560
阅读 392
JAVA
class SelfBounded<T extends SelfBounded<T>> {..}
我们把SelfBounded称为古怪的循环泛型(CRG),看起来很复杂,先把泛型参数提出来研究下:T extends SelfBounded<T>,这个类型参数T继承自一个泛型类型,这个泛型类型接受参数化类型T作为其类型参数。Crankish Round Generics
自限定类型:导出类被当作类型参数传递给泛型基类,这个导出类就被称为自限定类型。
自限定只能强制作用于继承关系,而CRG只接受一个泛型基类为自己的自限定类型来作为其泛型参数。
// 正在定义的类当作类型参数传递给基类class Derived2 extends SelfBounded<Derived2> { } // OKclass OtherType { }// ! class Derived3 extends SelfBounded<OtherType> { } // ERROR
Derived2可以作为SelfBounded的类型参数,因为OtherType并不是SelfBounded<OtherType>的子类,所以不能作为SelfBounded的合法泛型参数。
public class BasicHolder<T> {T element;void set(T arg) { element = arg; }T get() { return element; }void f() {System.out.println(element.getClass().getSimpleName());}} ///:~
这是一个普通的泛型类型,对于上面这个泛型类型,我们来自定义一个自限定类型。
// Subtype是一个自限定类型class Subtype extends BasicHolder<Subtype> { }public class CRGWithBasicHolder {public static void main(String[] args) {Subtype st1 = new Subtype(), st2 = new Subtype();// set(..)和get()方法应该被注意st1.set(st2);Subtype st3 = st1.get();st1.f();}} /* Output:Subtype*///:~
注意:我们定义的一个自限定类型Subtype接受的参数和返回值具有Subtype类型。看起来像是:基类(泛型类)用导出类代替了其类型参数,这就意味着泛型基类变成了一种其所有导出类的公共功能的模版,这些功能对于其所有泛型参数和返回值,将使用导出类型。
当然,BasicHolder这个普通的泛型类可以使用任何类型作为其泛型参数,就像下面看到的这样:
class Other { }class BasicOther extends BasicHolder<Other> { }public class Unconstrained {public static void main(String[] args) {BasicOther b = new BasicOther();b.set(new Other());Other other = b.get();b.f();}} /* Output:Other*///:~
对于Subtype这个自限定类型而言,其基类无论是BasicHolder<T>普通泛型还是BasicHolder<T extends BasicHolder<T>>CRG都不会对它产生什么影响。可是对与BasicOther这个普通类,其基类却只能是BasicHolder<T>,所以CRG并没有什么特别的,只是比普通泛型多了一些约束而已。
回到本文最开始的那个CRG——古怪的循环泛型SelfBounded<T extends SelfBounded<T>>,看看它能干些什么。
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 B extends SelfBounded<A> { } // Also OKclass C extends SelfBounded<C> {C setAndGet(C arg) {set(arg);return get();}}class D { }// Can't do this:// Compile error: Type parameter D is not within its bound// ! class E extends SelfBounded<D> {}// Alas, you can do this, so you can't force the idiom:class F extends SelfBounded { }public class SelfBounding {public static void main(String[] args) {A a = new A();a.set(new A());a = a.set(new A()).get();a = a.get();C c = new C();c = c.setAndGet(new C());}} ///:~
自限定类型的价值在于使用它们可以产生协办参数类型——方法参数类型会随子类而变化。在之前的文章中《继承与实现》已经讲过Java是支持协办返回类型的。
class BaseFace2<T extends BaseFace2<T>> { void setObject(T t) { } }class DerivedFace2 extends BaseFace2<DerivedFace2> { } // 自限定类型public class OrdinaryArguments {static void test(DerivedFace2 df, BaseFace2 bf) {df.setObject(df);// df.setObject(bf); // ERRORbf.setObject(bf);bf.setObject(df);}public static void main(String[] args) {test(new DerivedFace2(), new BaseFace2());}} ///:~