[关闭]
@lemonguge 2015-06-23T02:34:15.000000Z 字数 2560 阅读 392

泛型(三)

JAVA


自限定的类型

  1. class SelfBounded<T extends SelfBounded<T>> {..}

我们把SelfBounded称为古怪的循环泛型(CRG),看起来很复杂,先把泛型参数提出来研究下:T extends SelfBounded<T>,这个类型参数T继承自一个泛型类型,这个泛型类型接受参数化类型T作为其类型参数。Crankish Round Generics

自限定类型:导出类被当作类型参数传递给泛型基类,这个导出类就被称为自限定类型。

自限定只能强制作用于继承关系,而CRG只接受一个泛型基类为自己的自限定类型来作为其泛型参数。

  1. // 正在定义的类当作类型参数传递给基类
  2. class Derived2 extends SelfBounded<Derived2> { } // OK
  3. class OtherType { }
  4. // ! class Derived3 extends SelfBounded<OtherType> { } // ERROR

Derived2可以作为SelfBounded的类型参数,因为OtherType并不是SelfBounded<OtherType>的子类,所以不能作为SelfBounded的合法泛型参数。

  1. public class BasicHolder<T> {
  2. T element;
  3. void set(T arg) { element = arg; }
  4. T get() { return element; }
  5. void f() {
  6. System.out.println(element.getClass().getSimpleName());
  7. }
  8. } ///:~

这是一个普通的泛型类型,对于上面这个泛型类型,我们来自定义一个自限定类型。

  1. // Subtype是一个自限定类型
  2. class Subtype extends BasicHolder<Subtype> { }
  3. public class CRGWithBasicHolder {
  4. public static void main(String[] args) {
  5. Subtype st1 = new Subtype(), st2 = new Subtype();
  6. // set(..)和get()方法应该被注意
  7. st1.set(st2);
  8. Subtype st3 = st1.get();
  9. st1.f();
  10. }
  11. } /* Output:
  12. Subtype
  13. *///:~

注意:我们定义的一个自限定类型Subtype接受的参数和返回值具有Subtype类型。看起来像是:基类(泛型类)用导出类代替了其类型参数,这就意味着泛型基类变成了一种其所有导出类的公共功能的模版,这些功能对于其所有泛型参数和返回值,将使用导出类型。

当然,BasicHolder这个普通的泛型类可以使用任何类型作为其泛型参数,就像下面看到的这样:

  1. class Other { }
  2. class BasicOther extends BasicHolder<Other> { }
  3. public class Unconstrained {
  4. public static void main(String[] args) {
  5. BasicOther b = new BasicOther();
  6. b.set(new Other());
  7. Other other = b.get();
  8. b.f();
  9. }
  10. } /* Output:
  11. Other
  12. *///:~

对于Subtype这个自限定类型而言,其基类无论是BasicHolder<T>普通泛型还是BasicHolder<T extends BasicHolder<T>>CRG都不会对它产生什么影响。可是对与BasicOther这个普通类,其基类却只能是BasicHolder<T>,所以CRG并没有什么特别的,只是比普通泛型多了一些约束而已。

回到本文最开始的那个CRG——古怪的循环泛型SelfBounded<T extends SelfBounded<T>>,看看它能干些什么。

  1. class SelfBounded<T extends SelfBounded<T>> {
  2. T element;
  3. SelfBounded<T> set(T arg) {
  4. element = arg;
  5. return this;
  6. }
  7. T get() { return element; }
  8. }
  9. class A extends SelfBounded<A> { }
  10. class B extends SelfBounded<A> { } // Also OK
  11. class C extends SelfBounded<C> {
  12. C setAndGet(C arg) {
  13. set(arg);
  14. return get();
  15. }
  16. }
  17. class D { }
  18. // Can't do this:
  19. // Compile error: Type parameter D is not within its bound
  20. // ! class E extends SelfBounded<D> {}
  21. // Alas, you can do this, so you can't force the idiom:
  22. class F extends SelfBounded { }
  23. public class SelfBounding {
  24. public static void main(String[] args) {
  25. A a = new A();
  26. a.set(new A());
  27. a = a.set(new A()).get();
  28. a = a.get();
  29. C c = new C();
  30. c = c.setAndGet(new C());
  31. }
  32. } ///:~

自限定类型的价值在于使用它们可以产生协办参数类型——方法参数类型会随子类而变化。在之前的文章中《继承与实现》已经讲过Java是支持协办返回类型的。

  1. class BaseFace2<T extends BaseFace2<T>> { void setObject(T t) { } }
  2. class DerivedFace2 extends BaseFace2<DerivedFace2> { } // 自限定类型
  3. public class OrdinaryArguments {
  4. static void test(DerivedFace2 df, BaseFace2 bf) {
  5. df.setObject(df);
  6. // df.setObject(bf); // ERROR
  7. bf.setObject(bf);
  8. bf.setObject(df);
  9. }
  10. public static void main(String[] args) {
  11. test(new DerivedFace2(), new BaseFace2());
  12. }
  13. } ///:~
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注