gpt4 book ai didi

java - 在类级别或方法级别泛型之间进行选择

转载 作者:行者123 更新时间:2023-11-29 04:39:49 24 4
gpt4 key购买 nike

如何在泛型类型的类级别或方法级别定义之间进行选择?下面我有 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/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com