Java思维——泛型
关键词:类,对象,参数,继承,泛型
自有界类型
在Java泛型中,会定期出现一个相当令人费解的习语。这是它看起来的样子:
class SelfBoundedlt;T extends SelfBoundedlt;Tgt;gt; { // ...
这有两种镜子相互指向的令人眼花缭乱的效果,一种无限的反射。类SelfBounded接受一个泛型参数T,T受一个界的约束,并且bound是自有界的,以T为参数。
当您第一次看到它时,很难对其进行解析,而且它强调了extends关键字在与边界一起使用时,与用于创建子类时绝对不同。
随机重复的泛型
为了理解自绑定类型的含义,让我们从一个更简单的习语开始,不带自绑定。
不能直接从泛型参数继承。但是,您可以从在自己的定义中使用该泛型参数的类继承。也就是说,你可以说:
//: generics/CuriouslyRecurringGeneric.java
class GenericTypelt;Tgt; {}
public class CuriouslyRecurringGeneric
extends GenericTypelt;CuriouslyRecurringGenericgt; {} ///:~
这可以被称为JimCoplien在C 中的奇怪循环泛型(CRG)。“奇怪的重复”部分指的是您的类相当奇怪地出现在它自己的基类中的事实。
为了理解这意味着什么,试着大声说:“我正在创建一个新类,它继承了一个以我的类名为参数的泛型类型。”当给定派生类名时,泛型基类型可以实现什么?Java中的泛型是关于参数和返回类型的,因此它可以生成一个基类,将派生类型用于其参数和返回类型。它还可以将派生类型用于字段类型,即使这些字段类型将被删除为对象。下面是一个表示以下内容的泛型类:
//: generics/BasicHolder.java
public class BasicHolderlt;Tgt; {
T element;
void set(T arg) { element = arg; }
T get() { return element; }
void f() {
System.out.println(element.getClass().getSimpleName());
}
} ///:~
它是一种普通的泛型类型,具有接受和生成参数类型对象的方法,以及对存储字段进行操作的方法(尽管它仅对该字段执行对象操作)。
我们可以用BasicHolder来描述一个奇怪的重复出现的泛型:
//: generics/CRGWithBasicHolder.java
class Subtype extends BasicHolderlt;Subtypegt; {}
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();
}
} /* Output:
Subtype
*///:~
注意这里有一点很重要:新的类Subtype接受参数并返回Subtype的值,而不仅仅是基类BasicHolder。这就是CRG的本质:基类用派生类替换其参数。这意味着泛型基类将成为其所有派生类的通用功能的模板,但该功能将对其所有参数和返回值使用派生类型。也就是说,在生成的类中将使用确切的类型而不是基类型。所以在Subtype中,set()的参数和get()的返回类型都是子类型。
自边界
BasicHolder可以使用任何类型作为其泛型参数,如下所示:
//: generics/Unconstrained.java
class Other {}
class BasicOther extends BasicHolderlt;Othergt; {}
public class Unconstrained {
public static void main(String[] args) {
BasicOther b = new BasicOther(), b2 = new BasicOther();
b.set(new Other());
Other other = b.get();
b.f();
}
} /* Output:
Other
*///:~
自绑定需要额外的一步,即强制将泛型用作自己的绑定参数。看看结果类可以和不能被使用的方式:
//: generics/SelfBounding.java
class SelfBoundedlt;T extends SelfBoundedlt;Tgt;gt; {
T element;
SelfBoundedlt;Tgt; set(T arg) {
element = arg;
return this;
}
T get() { return element; }
}
class A extends SelfBoundedlt;Agt; {}
class B extends SelfBoundedlt;Agt; {} // Also OK
class C extends SelfBoundedlt;Cgt; {
C setAndGet(C arg) { set(arg); return get(); }
}
class D {}
//不能这样做:
//类E扩展了自有界的lt;Dgt;{}
//编译错误:类型参数D不在其范围内
//你可以做到这一点,所以你不能强迫这个成语:
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());
}
} ///:~
自边界所做的是需要在这样的继承关系中使用类:
class A extends SelfBoundedlt;Agt; {}
这迫使您将定义为参数的类传递给基类。
参数自边界的附加值是多少?类型参数必须与所定义的类相同。正如你在B类的定义中所看到的,你也可以从一个使用另一个自有界参数的自有界函数中派生出来,尽管主要的用途似乎是你在a类中看到的。试图定义E表明你不能使用一个非自有界的类型参数。
不幸的是,F编译时没有警告,因此自绑定习惯用法是不可执行的。如果这真的很重要,可能需要一个外部工具来确保未使用原始类型代替参数化类型。
请注意,您可以删除约束,所有类仍将编译,但E也将编译:
//: generics/NotSelfBounded.java
public class NotSelfBoundedlt;Tgt; {
T element;
NotSelfBoundedlt;Tgt; set(T arg) {
element = arg;
return this;
}
T get() { return element; }
}
class A2 extends NotSelfBoundedlt;A2gt; {}
class B2 extends NotSelfBoundedlt;A2gt; {}
class C2 extends NotSelfBoundedlt;C2gt; {
C2 setAndGet(C2 arg) { set(arg); return get(); }
}
class D2 {}
//现在这就可以了:
class E2 extends NotSelfBoundedlt;D2gt; {} ///:~
因此,很明显,自边界约束只会强制继承关系。如果使用自边界,则知道该类使用的类型参数将与使用该参数的类的基本类型相同。它迫使任何使用该类的人遵循该形式。
也可以对通用方法使用自边界:
//: generics/SelfBoundingMethods.java
public class SelfBoundingMethods {
static lt;T extends SelfBoundedlt;Tgt;gt; T f(T arg) {
return arg.set(arg).get();
}
public static void main(String[] args) {
A a = f(new A());
}
} ///:~
这将防止该方法应用于除所示形式的自有界参数之外的任何对象。
参数协方差
自边界类型的价值在于,它们生成协变参数类型方法参数类型随子类而变化。
尽管自绑定类型也会产生与子类类型相同的返回类型,但这并不重要,因为Java SE5中引入了协变返回类型:
//: generics/CovariantReturnTypes.java
class Base {}
class Derived extends Base {}
interface OrdinaryGetter {
Base get();
}
interface DerivedGetter extends OrdinaryGetter {
//被覆盖方法的返回类型允许发生变化:
Derived get();
}
public class CovariantReturnTypes {
void test(DerivedGetter
剩余内容已隐藏,支付完成后下载完整资料
英语原文共 9 页,剩余内容已隐藏,支付完成后下载完整资料
资料编号:[595983],资料为PDF文档或Word文档,PDF文档可免费转换为Word
课题毕业论文、文献综述、任务书、外文翻译、程序设计、图纸设计等资料可联系客服协助查找。