如何在泛型类的类级别或方法级别定义之间进行选择?下面我有2个示例,其中包含针对某些问题的替代(正确)实现。我试图了解这些差异,以及为什么我会选择其中一个。
示例1:
给定一些处理搜索树的算法。为了帮助用户进行调试,算法中的某些状态会触发事件。用户可以实现监听这些事件的EventListener
,例如一些记录器实用程序。
public Node<N extends Number>{ .. }
事件可以通过以下两种方式实现:
选项1 :(班级)
public class PruneNodeEvent<N extends Number> extends EventObject
{
public final Node<N> node; //Node being pruned
public PruneNodeEvent(Object source, Node<N> node)
{
super(source);
this.node = node;
}
}
选项2 :(方法级别)
public class PruneNodeEvent extends EventObject
{
public final Node<? extends Number> node; //Node being pruned
public PruneNodeEvent(Object source, Node<? extends Number> node)
{
super(source);
this.node = node;
}
}
应该考虑选择一个而不是另一个?
示例2: 给出一些听取Decisions的算法的抽象实现。每次做出新的决策时,算法都会更新其数据结构,但不会存储决策。由于这是一个抽象类(模板),我们不知道最终用户将如何使用此类。我们再次有两个选择:
选项1 :(班级)
public abstract class AbstractAlgorithm<T extends Data>
implements DecisionListener<T> {
@Override
public void makeDecision(Decision<T> d)
{
}
@Override
public void reverseDecision(Decision<T> d)
{
}
}
选项2 :(方法级别)
public abstract class AbstractAlgorithm implements DecisionListener
{
@Override
public void makeDecision(Decision<? extends Data> d) {
}
@Override
public void reverseDecision(Decision<? extends Data> d) {
}
}
应该考虑选择一个而不是另一个?
鼓励在设计通用类(ala Effective Java 2nd Edition)时包含有关Dos,Don'ts和考虑因素的好参考资料以支持您的答案。
答案 0 :(得分:3)
示例1
这两者之间的主要区别在于您可以使用node
。
为了完整性,我们只需添加第三个选项:
public final Node<? super Number> node;
请记住首字母缩略词 PECS :
Producer Extends,Consumer Super
在第二个选项中,Node<? extends T> node
是制作者:您只能调用在其上生成T
的方法。
T instanceOfT = node.get();
但您无法使用null
以外的参数调用使用者方法:
node.accept(null); // OK.
node.accept(instanceOfT); // Compiler error.
在第三个选项中,Node<? super T> node
是使用者:您只能在其上调用采取 a T
的方法,例如
node.accept(instanceOfT);
但您无法调用生产者方法并将其结果分配给依赖于T
的类型:
Object obj = node.get(); // OK.
List<?> list = node.getList(); // OK.
T t = node.get(); // Compiler error.
List<T> listT = node.getList(); // Compiler error.
在第一个选项中,Node<T> node
都是生产者和消费者,因为它是选项2和3的交集(同时为{{1 }}和<? extends T>
是<? super T>
):
<T>
因此,3个选项之间的选择取决于您需要对T t = node.get(); // OK.
node.accept(t); // OK.
:
node
,请选择T
或<T>
; <? extends T>
,请选择T
或<T>
; <? super T>
,请选择T
。示例2
如果您只想为<T>
的特定参数类型调用方法,请使用第一个,例如
Decision
如果您希望能够为具有相同AbstractAlgorithm<StringData> foo = new AbstractAlgorithm<>();
foo.makeDecision(new Decision<StringData>()); // OK.
foo.makeDecision(new Decision<IntegerData>()); // Compiler error.
的任何类型调用方法,请使用第二个,例如
AbstractAlgorithm