Java思维——泛型外文翻译资料

 2023-03-15 04:03

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

您需要先支付 30元 才能查看全部内容!立即支付

课题毕业论文、文献综述、任务书、外文翻译、程序设计、图纸设计等资料可联系客服协助查找。