- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
如何在泛型类型的类级别或方法级别定义之间进行选择?下面我有 2 个示例,其中包含针对某些问题的替代(正确)实现。我试图了解其中的差异,以及为什么我会选择一个而不是另一个。
示例 1:给定一些处理搜索树的算法。为了帮助用户进行调试,算法中的某些状态会触发一个事件。用户可以实现一个 EventListener
来监听这些事件,例如一些记录器实用程序。
public Node<N extends Number>{ .. }
事件可以通过以下两种方式实现:
选项 1:(类(class))
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:给定一个监听决策的算法的一些抽象实现。每次做出新的决策时,算法都会更新其数据结构,但不会存储决策。由于这是一个抽象类(模板),我们不知道最终用户将如何使用这个类。同样,我们有 2 个选择:
选项 1:(类(class))
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) {
}
}
选择其中一个应该考虑哪些因素?
我们鼓励在设计泛型类(如 Effective Java 第 2 版)时包含有关 Dos、Don'ts 和注意事项的良好引用以支持您的回答。
最佳答案
Example 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
是一个消费者:您只能在其上调用接受 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 的交集(同时是 <? extends T>
和 <? super T>
的类型是 <T>
):
T t = node.get(); // OK.
node.accept(t); // OK.
因此,在这 3 个选项之间的选择取决于您需要对 node
做什么:
T
s,选择 <T>
或 <? extends T>
;T
s,选择 <T>
或 <? super T>
;T
s,选择<T>
.Example 2
如果您只想调用Decision
的特定参数类型的方法,请使用第一个。 ,例如
AbstractAlgorithm<StringData> foo = new AbstractAlgorithm<>();
foo.makeDecision(new Decision<StringData>()); // OK.
foo.makeDecision(new Decision<IntegerData>()); // Compiler error.
如果您希望能够调用具有相同 AbstractAlgorithm
的任何类型的方法,请使用第二个。 ,例如
AbstractAlgorithm foo = new AbstractAlgorithm();
foo.makeDecision(new Decision<StringData>()); // OK.
foo.makeDecision(new Decision<IntegerData>()); // OK.
关于java - 在类级别或方法级别泛型之间进行选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39679876/
我是一名优秀的程序员,十分优秀!