【问题标题】:How type inference works in Java or why mockito even compile类型推断在 Java 中是如何工作的,或者为什么 mockito 甚至可以编译
【发布时间】:2016-11-15 11:32:59
【问题描述】:

尝试fix method resolution in standalone java parser 我发现a code in mockito 我不明白。如果我基于 mockito 代码创建小测试:

package org.mockitousage.matchers;

import java.util.Collection;

public class MoreMatchersTest {
    public interface IMethods {
        String simpleMethod(String argument);
        String simpleMethod(Collection<?> collection);
        String simpleMethod(Object argument);
    }

    private IMethods mock;

    public static <T> T any() {
        return null;
    }

    public static <T> T verify(T m) {
        return m;
    }

    public void any_should_be_actual_alias_to_anyObject() {
        verify(mock).simpleMethod(any());
    }
}

正如我所料,我遇到了编译错误:

Error:(23, 21) java: reference to simpleMethod is ambiguous
  both method simpleMethod(java.lang.String) in org.mockitousage.matchers.MoreMatchersTest.IMethods and method simpleMethod(java.util.Collection<?>) in org.mockitousage.matchers.MoreMatchersTest.IMethods match

但不知何故,mockito 编译成功。您能否解释一下为什么 mockito 中的代码编译(以及 &lt;T&gt;any 编译器选择的专业化)或如何修改我的示例以便它也可以编译(我知道我可以将 any() 转换为特定类型或删除 @ 的重载987654329@ 但我想尽可能接近模拟代码)。

命令行输出:

> javac -version
javac 1.8.0_111

> javac -d C:\w\MockitoTest\out\production\MockitoTest -classpath C:\w\MockitoTest\out\production\MockitoTest -sourcepath C:\w\MockitoTest\src -g -source 8 -target 8 C:\w\MockitoTest\src\org\mockitousage\matchers\MoreMatchersTest.java
C:\w\MockitoTest\src\org\mockitousage\matchers\MoreMatchersTest.java:23: error: reference to simpleMethod is ambiguous
        verify(mock).simpleMethod(any());
                    ^
  both method simpleMethod(String) in IMethods and method simpleMethod(Collection<?>) in IMethods match
1 error

> javac -d C:\w\MockitoTest\out\production\MockitoTest -classpath C:\w\MockitoTest\out\production\MockitoTest -sourcepath C:\w\MockitoTest\src -g -source 7 -target 7 C:\w\MockitoTest\src\org\mockitousage\matchers\MoreMatchersTest.java
warning: [options] bootstrap class path not set in conjunction with -source 1.7
1 warning

【问题讨论】:

  • “你能解释一下为什么mockito compile中的代码”你指的是哪个代码?代码和你的不一样。
  • 好吧,Java 8 中的类型推断得到了大修,JLS 中的一章docs.oracle.com/javase/specs/jls/se8/html/jls-18.html。在 Java 8 之前,推断类型应该是 Object,但在版本 8 中似乎更复杂
  • @borys-zibrov 我添加了来自 oracle jdk 8 update 111 的 javac 输出
  • @borys-zibrov - 我正在使用来自 git master 的版本,但你是对的 - mockito_main 和 mockito_test 模块使用 Java 6 语言级别(所有其他模块和项目本身使用 Java 8,我只检查了之前的项目本身) - 你能添加一个答案,我会接受它。

标签: java generics


【解决方案1】:

在这种情况下,您不需要指定类型,因为编译器绑定到 Object。

这一行

 verify(mock).simpleMethod(any()); // bind to simpleMethod(Object)

使用 Java 8 更新 101 可以很好地编译(mockito 和您的示例)。

【讨论】:

  • 是的,它应该可以工作,我同意。 Mockito 没有魔法。 @iSanych,也许是您的 JDK 中的错误?试试 Oracle 的最新版本。
  • 当我在idea中将项目语言级别指定为java 7时,它正在使用java 8进行编译,而当它是java 8时它会失败。是的,我知道它在哪里解决我试图理解为什么跨度>
  • @borys-zibrov 我怀疑它是 jdk 错误,也许想法运行它有一些选项 - 试图获得完整的日志想法如何运行 java。并且具有 java 级别 8 的相同 jdk 编译 mockito 没有错误。尝试使用独立的想法解析器时,我只有方法解析方面的问题。
  • 为目标 7 和 8 的 java 8 编译器添加了命令行输出
  • @ISanych 我将这个类添加到了 mockito 存储库,它编译得很好。将它自己复制到一个项目中,它会得到你看到的错误。
【解决方案2】:

所以,首先,Java 8 定义了类型推断规则,详细描述here,这样一些在 1.7 或 1.6 下可以顺利编译的代码在 1.8 下不再编译,例如示例代码赢了't 确实编译:

public class MoreMatchersTest {
    public interface IMethods {
        String simpleMethod(String argument);
        String simpleMethod(Collection<?> collection);
        String simpleMethod(Object argument);
    }

    private IMethods mock;

    public static <T> T any() {
        return null;
    }

    public static <T> T verify(T m) {
        return m;
    }

    public void any_should_be_actual_alias_to_anyObject() {
        verify(mock).simpleMethod(any());
    }
}

对此有多个问题,例如,请参阅 herehere

所以问题是为什么 Mockito 似乎有效,答案很简单。 Mockito 2.x 版本使用 targetCompatibility = 1.6 (github) 编译,甚至 Mockito on master 对某些模块使用语言级别 1.6。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-04
    相关资源
    最近更新 更多