【问题标题】:Use generic Wildcard in interface level java在接口级别java中使用通用通配符
【发布时间】:2017-08-22 01:58:47
【问题描述】:

这与java通用通配符有关。我需要了解这是如何发生的并需要解决方案。

例如:我有一个接口名称处理器。

public interface Processer<X> {
    <P> void process(P parent, X result);
}

我想将 P 作为通配符。但定义时不允许使用通配符(?)。

当我实现这个接口并让 IDE 生成实现的方法时,它生成如下。

public class FirstProcesser implements Processer<String> {
    @Override
    public <P> void process(P parent, String result) {

    }
}

我想修改这个实现。

public class FirstProcesser implements Processer<String> {
    @Override
    public void process(User parent, String result) {

    }
}

但是它给出了 FirstProcesser 应该是抽象的或实现所有抽象方法的编译错误。

我需要知道为什么会发生这种情况以及解决方案。

【问题讨论】:

  • 似乎很明显为什么它正在发生。 UserP 不是(不一定)相同的类型,因此它是无效的覆盖。如果你想要一个解决方案,你需要更清楚你想要完成的事情。
  • 因为 P 代表通用 P 可以是任何东西。我说的对吗?
  • 从某种意义上说,您可以使用任何特定的P 调用它。并不是说你可以用任何P覆盖它。
  • 如果你有Processor&lt;String&gt; processor = ...,值可以是FirstProcessorSecondProcessor,等等...如果我们要调用processor.process(..., ""),那么强制第一个参数是@987654332 @? FirstProcessor 试图强制执行它,但是如果 processor 的值从 FirstProcessor 切换到 SecondProcessor,并且 SecondProcessor 想要接受除 User 之外的其他值(这可能是你这样做,否则P 可能只是User)?这是没有意义的,这就是为什么不允许这样做。
  • 感谢您的评论。当我实施诸如责任链模式之类的东西时,这个问题就出现了。所以我已经实现了这是超级类并使用它。然后进程将相关处理器相应地绑定到下一个职责。

标签: java generics wildcard


【解决方案1】:

覆盖

你不能覆盖一个方法 (通用与否) 一个采用更窄的参数类型。 如果可以,编译器将无法判断任何给定的方法调用是否会 (将来时) 合法。

一个根本没有任何泛型的示例,它将失败并出现完全相同的错误:

public class X {
    public void f(Object o) {
    }
}

class Y extends X {
    @Override
    public void f(String s) {
    }
}

编译失败:

X.java:8: error: method does not override or implement a method from a supertype
    @Override
    ^
1 error

如果它是合法的,那么即使是非常简单的方法也无法可靠地编译,例如:

public static void f(X x) {
    x.f(5);
}

如果x 是一个实际的X 对象,则该代码可以正常工作,但如果xY 子类型,它就会失败,因为5 不是String。 这就是为什么上面定义的Y.f是不允许覆盖X.f的原因。

通过将 FirstProcesser 更改为仅接受 User 对象,您将导致同样的问题。

责任链

chain of responsibility pattern on Wikipedia 看起来不太像您要构建的东西。 我能想到两件事你可能会尝试做......

1。 如果parent 参数应该是链中的前一个处理程序,那么它应该是Processer&lt;X&gt; 类型:

public interface Processer<X> {
    void process(Processer<X> parent, X result);
}

class StringProcesser implements Processer<String> {
    @Override
    public void process(Processer<String> parent, String result) {
    }
}

2。 如果parent 的类型是决策过程的一部分,则每个处理程序都应存储它可以处理的Class 对象的集合。 然后process 方法应该查看parent.getClass() 是否在该集合中。

部分定义可能类似于:

public interface Processer<X> {
    void process(Class<?> parent, X result);
}

class StringProcesser implements Processer<String> {
    private Set<Class<?>> classes = new HashSet<Class<?>>();

    public StringProcesser(final Iterable<Class<?>> classes) {
        for (final Class<?> c : classes) {
            this.classes.add(c);
        }
    }

    @Override
    public void process(Class<?> parent, String result) {
        if (this.classes.contains(parent)) {
            System.err.println("Handling...");
            System.out.println(result);
            return;
        }
        System.err.println(
          "Can't handle.  Try next Processer."
        );
        // ...
    }

}

请注意,泛型类型参数 &lt;X&gt; 和通配符 &lt;?&gt; 的显示位置取决于您要执行的操作。

PS:“处理器”应拼写为“处理器”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多