600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > Java泛型(8):自限定参数协变

Java泛型(8):自限定参数协变

时间:2021-12-05 10:54:09

相关推荐

Java泛型(8):自限定参数协变

自限定

自限定将强制泛型当做自己的边界参数来使用。自限定所做的,就是要求在继承关系中,像下面这样使用这个类:

class A extends SelfBounded<A> {}

它的意义是可以保证类型参数必须与正在被定义的类相同自限定只能强制作用于继承关系。如果使用自限定,就应该了解这个类所用的类型参数将与使用这个参数的类具有相同的基本类型。

下面是一个自限定的例子【1】:

1 class SelfBounded<T extends SelfBounded<T>> { 2T element; 3SelfBounded<T> set(T arg) { 4 element = arg; 5 return this; 6} 7T get() { return element; } 8 } 9 10 class A extends SelfBounded<A> {}11 class B extends SelfBounded<A> {} // It's OK.12 13 class C extends SelfBounded<C> {14C setAndGet(C arg) { set(arg); return get(); }15 }16 17 class D {}18 // class E extends SelfBounded<D> {} // [Compile error]: Type parameter D is not within its bound19 20 public class SelfBounding {21public static void main(String[] args) {22 A a = new A();23 a.set(new A());24 a = a.set(new A()).get();25 a = a.get();26 C c = new C();27 c = c.setAndGet(new C());28}29 }

我们发现class E是不能编译的。如果移除自限定这个限制(class SelfBounded<T>),这样E就可以编译了。但是就不能限制E这样的非自限定类型继承SelfBounded类了。

参数协变

先看一个协变返回类型的例子【2】:

1 class Base {} 2 class Derived extends Base {} 3 4 interface OrdinaryGetter { 5Base get(); 6 } 7 8 interface DerivedGetter extends OrdinaryGetter { 9// DerivedGetter.get()覆盖了OrdinaryGetter.get()10@Override Derived get();11 }12 13 public class CovariantReturnTypes {14void test(DerivedGetter d) {15 Derived result1 = d.get(); // 调用的DerivedGetter.get()16 Base result2 = d.get(); // 也调用的DerivedGetter.get()17}18 }

而自限定泛型将产生确切的导出类型作为其返回值。请看例【3】:

1 interface GenericGetter<T extends GenericGetter<T>> { 2T get(); 3 } 4 5 interface Getter extends GenericGetter<Getter> {} 6 7 public class GenericsAndReturnTypes { 8void test(Getter g) { 9 Getter result1 = g.get();10 GenericGetter result2 = g.get(); // Also the base type11}12 }

例【2】可以证明,返回值并不是区分两个不同方法的途径。而下面的例【4】则说明参数类型可以区分两个不同的方法。所以例【2】是覆盖(override)而例【4】是重载(overload)。

1 class OrdinarySetter { 2void set(Base base) { 3 System.out.println("OrdinarySetter.set(Base)"); 4} 5 } 6 7 class DerivedSetter extends OrdinarySetter { 8// @Override // [Compile Error]: Can't override. It's overload not override! 9void set(Derived derived) {10 System.out.println("DerivedSetter.set(Derived)");11}12 }13 14 // 在非泛型代码中,参数类型不能随子类型发生变化。15 public class OrdinaryArguments {16public static void main(String[] args) {17 Base base = new Base();18 Derived derived = new Derived();19 DerivedSetter ds = new DerivedSetter();20 ds.set(derived); // 调用DerivedSetter的set21 ds.set(base); // 调用OrdinarySetter的set22}23 }

但是,在使用自限定类型时,在导出类中只有一个方法,并且这个方法接受导出类型而不是基类型作为参数。例子【5】:

1 interface SelfBoundSetter<T extends SelfBoundSetter<T>> { 2void set(T arg); 3 } 4 5 interface Setter extends SelfBoundSetter<Setter> {} 6 7 public class SelfBoundingAndCovariantArguments { 8void testA(Setter s1, Setter s2, SelfBoundSetter sb1, SelfBoundSetter sb2) { 9 s1.set(s2);10 // 编译器不能识别将基类型当做参数传递给set的尝试,因为没有任何方法具有这样的签名。事实上,这个参数已经被覆盖。11 // s1.set(sb1); // [Compile Error]: set(Setter) in SelfBoundSetter<Setter> cannot be applied to (SelfBoundSetter)12 sb1.set(s1);13 sb1.set(sb2);14}15 }

如果上例不使用自限定类型,普通继承机制就会介入,而你将能够重载,就像在非泛型的情况下一样(自限定类型可以避免这种情况发生):

1 class GenericSetter<T> { // Not self-bounded 2void set(T arg){ 3 System.out.println("GenericSetter.set(Base)"); 4} 5 } 6 7 class DerivedGS extends GenericSetter<Base> { 8// @Override // [Compile Error]: Can't override. It's overload not override. 9void set(Derived derived){10 System.out.println("DerivedGS.set(Derived)");11}12 }13 14 public class PlainGenericInheritance {15public static void main(String[] args) {16 Base base = new Base();17 Derived derived = new Derived();18 DerivedGS dgs = new DerivedGS();19 dgs.set(derived);20 dgs.set(base); // Compiles: overloaded, not overridden!21}22 }

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。