Java 泛型和通配符 : How to make this code compile?

标签 java generics compiler-errors wildcard hamcrest

我正在使用 Hamcrest 1.2 编写一些匹配器库,但我很难使用 Java 通配符。当我尝试编译以下代码时

public class GenericsTest {

    public void doesNotCompile() {
        Container<String> container = new Container<String>();

        // this is the desired assertion syntax
        assertThat(container, hasSomethingWhich(is("foo")));
    }

    // these two are a custom made class and matcher; they can be changed

    public static class Container<T> {
        public boolean hasSomethingMatching(Matcher<T> matcher) {
            T something = null; // here is some application logic
            return matcher.matches(something);
        }
    }

    public static <T> Matcher<Container<T>> hasSomethingWhich(final Matcher<T> matcher) {
        return new TypeSafeMatcher<Container<T>>() {
            @Override
            protected boolean matchesSafely(Container<T> container) {
                return container.hasSomethingMatching(matcher);
            }
        };
    }

    // the following signatures are from the Hamcrest 1.2 library; they cannot be changed

    public static <T> void assertThat(T actual, Matcher<? super T> matcher) {
    }

    public static <T> Matcher<? super T> is(T value) {
        return null;
    }

    public interface Matcher<T> {
        boolean matches(Object item);
    }

    public static abstract class TypeSafeMatcher<T> implements Matcher<T> {
        @SuppressWarnings({"unchecked"})
        @Override
        public final boolean matches(Object item) {
            return matchesSafely((T) item);
        }

        protected abstract boolean matchesSafely(T item);
    }
}

它产生编译错误

$ javac GenericsTest.java
GenericsTest.java:7: <T>assertThat(T,GenericsTest.Matcher<? super T>) in GenericsTest cannot be applied to (GenericsTest
.Container<java.lang.String>,GenericsTest.Matcher<GenericsTest.Container<capture#928 of ? super java.lang.String>>)
        assertThat(container, hasSomethingWhich(is("foo")));
        ^
1 error

如何修改代码使其能够编译?我尝试了 ? super 的不同组合和 ? extends在 Container 类和 hasSomethingWhich 方法的签名中,但无法使其编译(不使用显式方法类型参数,但会产生难看的代码:GenericsTest.<String>hasSomethingWhich)。

也欢迎使用其他方法来创建简洁易读的断言语法。无论语法如何,它都应该接受一个 Container 和一个用于匹配 Container 内元素的 Matcher 作为参数。

最佳答案

is(T) matcher 返回一个签名为 Matcher<? super T> 的 Matcher .

因此,如果您解构 assertThat(container, hasSomethingWhich(is("foo"))) 行你真正拥有的是:

Matcher<? super String> matcher = is("foo");
assertThat(container, hasSomethingWhich(matcher));

第二行编译错误,因为你的hasSomethingWhich的签名方法需要参数 Matcher<T> .匹配 hamcrest 的 is(T) 的返回类型,您的签名应该是:

public static <T> Matcher<Container<T>> hasSomethingWhich(final Matcher<? super T> matcher)

(不同之处在于将参数从 Matcher<T> 更改为 Matcher<? super T>

这将强制您更改 hasSomethingWhich() 的签名也接受 Matcher<? super T>像这样:

public boolean hasSomethingMatching(Matcher<? super T> matcher)

Here是您发布的原始代码的完全修改版本,它为我编译成功。

关于Java 泛型和通配符 : How to make this code compile?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3831004/

相关文章:

java进程间通信

java - 使用 Java BigDecimal 提高准确性

java - 在java android中覆盖子类中的属性类型

java - 基于项目的Android应用

compiler-construction - VHDL编译器退出错误

java - java中获取泛型接口(interface)的注解值

scala - 不同类型List的通用unapply方法

c# - 通用方法和无效上下文异常

java - ASSIGNRES 类型的比较方法未定义

linux - fatal error : pthread/pthread_impl. h : No such file or directory #include <pthread/pthread_impl. h>