通过将新类型指定为generics的实际类型来扩展generics有什么好处
我在某处看到了这种模式:
class A extends B { }
通过将新类型指定为generics的实际类型,此结构对于扩展generics有点不寻常。 有什么用? 这个模式有名字吗? 有没有替代模式?
示例: https : //code.google.com/p/selenium/wiki/LoadableComponent
跳转到: public class EditIssue extends LoadableComponent {
编辑:阅读完回复后,我似乎需要改变编译器对类型检查的理解。 在我的脑海里,我的牛肉有这种模式,如果两个A需要相同,那么有没有办法不重复它们? 但似乎没有更好的方法将派生类的类型传播给父类。
当然,OOP的答案是A
是B
如果A
不是B
不是A
应该只用B
来构成B
来利用B
的function。
据推测, B
还有一些通用实现,它们利用了对generics类型的限制。
另一个用例是B
看起来像:
abstract class B> { public T createCopy(T t); }
现在,子类可以实现createCopy
,客户端代码可以安全地使用它而无需转换…例如
class A extends B { public A createCopy(A t) { return new A(t); //copy constructor } }
比较以上内容:
abstract class B { public B createCopy(B t); } class A extends B { public B createCopy(B t) { //Is the copy an A or a different subtype of B? We don't know. return new A(t); //copy constructor } }
在处理递归数据结构时,您可能会执行类似的操作。 例如,图形或树中的节点可以定义为其他节点的集合:
class Node extends AbstractList { ... }
同样,如果抽象/generics类型用于比较类似类型的对象,您可能会看到类似这样的内容,例如java.lang.Comparable
:
class MyObject implements Comparable { public int compareTo(MyObject other) { ... } }
举个例子:
E extends Comparable
这意味着E必须是一个知道如何与自身进行比较的类型,因此,递归类型定义。
不知道它是否有任何官方名称,但我会称之为递归generics模式 。
此模式与任何其他子类相同。 使用generics时真正发生的事情是JVM正在创建一个类的副本(实际上不是副本,但它有点类似),并用指定的类型替换generics使用的所有点。
所以,为了回答你的问题,所有这种模式都在用B
代替B
,其中A
所有用途都被A
类所取代。 这种情况的潜在用途是您为特定类定制数据结构(来自java.util.Collections
),例如使用bitshifts将Collection
压缩为较小的内存量。 我希望这是有道理的!
这确实令人困惑,因为A
和B
两种类型似乎依赖于彼此存在; 在普通的OOP中没有多大意义,那么它的用途是什么? 我发现了这种模式的3个用例。
作文转为inheritance
假设一个Node
有一个子节点列表。 通常的设计是通过构图
class Node ArrayList children = ...
有时为了获得较小的性能,人们会使用inheritance
class Node extends ArrayList // the super class represents the children...
这有点令人困惑,但没有什么难以理解的。 我们知道这只是一种方便,它并不试图传达一个节点是一个节点列表。
可以考虑LoadableComponent
这个用例。 它可以说是一种不太理想的设计而不是合成方法
class ComponentLoader C get(){...} class EditIssue final ComponentLoader loader = new ComponentLoader (){ @Override void load(){...} @Override void isLoaded(){...} }; EditIssue compo = ... compo.loader.get().doSomething();
设计师可能会发现这种方法更具锅炉性。
方法链接
而不是写作
foo.doA(); foo.doB();
很多人宁愿写作
foo.doA().doB();
不幸的是,该语言并不直接支持方法链,即使它正在成为越来越渴望的function。 解决方法是让doA()
返回foo
。 它有点脏但可以接受。
但是,如果foo
位于类型层次结构中,则解决方法将被破坏
class Bar Bar doA() class Foo extends Bar Foo doB(); foo.doA().doB(); // doesn't compile, since doA() returns Bar
所以有些人要求一种特殊的“自我型”来解决这个问题。 假设有一个关键字This
代表“自我类型”
class Bar This doA() foo.doA().doB(); // works, doA() returns the type of foo, which is Foo
看来方法链是“自我类型”的唯一用例,所以语言可能永远不会引入它(最好只支持方法链接)
人们发现generics为这个问题提供了一种解决方法
class Bar This doA() class Foo extends Bar Foo has a method "Foo doA()", inherited from Bar
这是A extends B
模式最常用的用例。 这是一个孤立的解决方法/技巧。 它在A和B之间的关系中没有添加语义。
约束This
也是一种流行的做法
class Bar>
这是丑陋和无用的,我强烈建议反对它。 只需使用“This”作为约定来表明它的用途。
LoadableComponent
也可以归入此用例。 在更简单的设计中我们可以做到
class LoadableComponent void ensureLoaded() class EditIssue extends LoadableComponent EditIssue compo = ... compo.ensureLoaded(); compo.doSomething();
为了支持最后两行的方法链接, LoadableComponent
以其当前forms设计,以便我们可以编写compo.get().doSomething()
更多的东西
所以前两个用例是一种黑客攻击。 如果A
和B
之间存在真正的约束怎么办?
而不是作为普通超类型, B
更多元,它描述了类型A
应该具有引用A
本身的一些属性。 这不是传统OOP的inheritance,它更抽象。 (虽然它仍然通过传统的inheritance机制实现,但可以想象该语言可以将其作为一个独立的概念来推广。)
这个用例是Comparable
的。 它描述了某种类型可以与自身进行比较。 由于它不是传统的OOP类型,理想情况下我们不应该声明具有静态类型Comparable
的对象。 我们在公共方法返回/参数类型中看不到它,它没有多大意义。 相反,我们看到的东西
> void sort(List )
这里的方法需要一个符合Comparable模式的类型。
(我真的不知道我在这节谈论的是什么)