这个 Java 方法调用的歧义在哪里?
Where is the ambiguity in this Java method call?
我收到一个我不理解的 "reference to make is ambiguous" 编译器错误。
我有这两个方法
public static <T> T make(String name, Class<T> parentClass,
boolean rethrowRuntimeExceptions,
Object... params) throws DLException
public static <T> T make(String name, Class<T> parentClass,
Object... params) throws DLException
这行代码被标记为不明确
String className = "clsNme";
String one = "1";
String two = "2";
SimpleFactory.make(className, Object.class, false, one, two);
这里是错误
both method <T#1>make(String,Class<T#1>,boolean,Object...) in SimpleFactory and method <T#2>make(String,Class<T#2>,Object...) in SimpleFactory match
[javac] where T#1,T#2 are type-variables:
[javac] T#1 extends Object declared in method <T#1>make(String,Class<T#1>,boolean,Object...)
[javac] T#2 extends Object declared in method <T#2>make(String,Class<T#2>,Object...)
布尔参数的存在不会使第一种方法比第二种方法更匹配吗?
如果重要,这是 PowerMock 测试的一部分这是完整的方法
public void makeCallsMakeWithFalse() throws Throwable {
Object expected = mock(Object.class);
String className = "clsNme";
String one = "1";
String two = "2";
spy(SimpleFactory.class);
doReturn(expected).when(SimpleFactory.class);
SimpleFactory.make(className, Object.class, false, one, two); // causes error
Object observed = SimpleFactory.make(className, Object.class, one, two); // doesn't cause error
assertEquals(expected, observed);
verifyStatic();
SimpleFactory.make(className, Object.class, false, one, two); // causes error
}
如果有帮助:我正在使用 javac 1.8.0_77、Mokito 1.10.19 和 Powermock 1.6.3.
问题出在
Object... params
调用时SimpleFactory.make(className, Object.class, false, one, two);
Java 将不知道是否将 "false" 装箱到布尔对象中并将其作为 "params" 可变参数数组(布尔扩展对象)的第一个参数传递并使用
make(String name, Class<T> parentClass, Object... params)
或者是否调用
make(String name, Class<T> parentClass, boolean rethrowRuntimeExceptions, Object... params)
因为该签名也可以在参数可变参数之前接受布尔值。
因此,为什么它是模棱两可的,两种方法签名都适用。
我想是因为编译器不知道你要不要把boolean参数包含在params中。我可以使用 4 个参数调用函数并将布尔值作为第三个参数传递,或者它可以使用 3 个参数调用函数并将布尔值添加到对象...参数。由于这种歧义,编译器不知道该怎么做。如果您需要更多信息,请告诉我
编译器首先尝试找到不涉及 autoboxing/unboxing 或 变量调用 的匹配签名。变量元数调用是指通过将参数列表作为最后一个参数(而不是数组)传递来调用可变参数方法。
在您的情况下,两者都涉及变量 arity 调用。发生这种情况时,将选择最具体的重载。对于您的情况,JLS 中定义的都不是更具体的。这本质上是因为类型 boolean
和 Object
都不是另一个类型的子类型。
稍微简化一下您的示例,以下内容无法编译。
static void foo(boolean b, Object... arr) {
}
static void foo(Object... arr) {
}
public static void main(String[] args) {
foo(true);
}
第一个版本不接受 Object
类型的单个参数,第二个版本不接受 boolean
类型的单个参数。因此两者都不是更具体。 (自动装箱只会使它 看起来 就好像您可以将 boolean
作为类型 Object
的参数传递一样。
另一方面,如果将 boolean
替换为 Boolean
,它会编译,因为 Boolean
是 Object
的子类型。
问题在于
Object... params
要解决歧义 - 更改如下代码
打电话
public static <T> T make(String name, Class<T> parentClass,
boolean rethrowRuntimeExceptions,
Object... params) throws DLException
这样称呼它:
SimpleFactory.make(className, Object.class, false, new Object[]{one, two});
和
打电话给
public static <T> T make(String name, Class<T> parentClass,
Object... params) throws DLException
这样称呼它:
SimpleFactory.make(className, Object.class, new Object[]{false,one, two});
我收到一个我不理解的 "reference to make is ambiguous" 编译器错误。
我有这两个方法
public static <T> T make(String name, Class<T> parentClass,
boolean rethrowRuntimeExceptions,
Object... params) throws DLException
public static <T> T make(String name, Class<T> parentClass,
Object... params) throws DLException
这行代码被标记为不明确
String className = "clsNme";
String one = "1";
String two = "2";
SimpleFactory.make(className, Object.class, false, one, two);
这里是错误
both method <T#1>make(String,Class<T#1>,boolean,Object...) in SimpleFactory and method <T#2>make(String,Class<T#2>,Object...) in SimpleFactory match
[javac] where T#1,T#2 are type-variables:
[javac] T#1 extends Object declared in method <T#1>make(String,Class<T#1>,boolean,Object...)
[javac] T#2 extends Object declared in method <T#2>make(String,Class<T#2>,Object...)
布尔参数的存在不会使第一种方法比第二种方法更匹配吗?
如果重要,这是 PowerMock 测试的一部分这是完整的方法
public void makeCallsMakeWithFalse() throws Throwable {
Object expected = mock(Object.class);
String className = "clsNme";
String one = "1";
String two = "2";
spy(SimpleFactory.class);
doReturn(expected).when(SimpleFactory.class);
SimpleFactory.make(className, Object.class, false, one, two); // causes error
Object observed = SimpleFactory.make(className, Object.class, one, two); // doesn't cause error
assertEquals(expected, observed);
verifyStatic();
SimpleFactory.make(className, Object.class, false, one, two); // causes error
}
如果有帮助:我正在使用 javac 1.8.0_77、Mokito 1.10.19 和 Powermock 1.6.3.
问题出在
Object... params
调用时SimpleFactory.make(className, Object.class, false, one, two);
Java 将不知道是否将 "false" 装箱到布尔对象中并将其作为 "params" 可变参数数组(布尔扩展对象)的第一个参数传递并使用
make(String name, Class<T> parentClass, Object... params)
或者是否调用
make(String name, Class<T> parentClass, boolean rethrowRuntimeExceptions, Object... params)
因为该签名也可以在参数可变参数之前接受布尔值。
因此,为什么它是模棱两可的,两种方法签名都适用。
我想是因为编译器不知道你要不要把boolean参数包含在params中。我可以使用 4 个参数调用函数并将布尔值作为第三个参数传递,或者它可以使用 3 个参数调用函数并将布尔值添加到对象...参数。由于这种歧义,编译器不知道该怎么做。如果您需要更多信息,请告诉我
编译器首先尝试找到不涉及 autoboxing/unboxing 或 变量调用 的匹配签名。变量元数调用是指通过将参数列表作为最后一个参数(而不是数组)传递来调用可变参数方法。
在您的情况下,两者都涉及变量 arity 调用。发生这种情况时,将选择最具体的重载。对于您的情况,JLS 中定义的都不是更具体的。这本质上是因为类型 boolean
和 Object
都不是另一个类型的子类型。
稍微简化一下您的示例,以下内容无法编译。
static void foo(boolean b, Object... arr) {
}
static void foo(Object... arr) {
}
public static void main(String[] args) {
foo(true);
}
第一个版本不接受 Object
类型的单个参数,第二个版本不接受 boolean
类型的单个参数。因此两者都不是更具体。 (自动装箱只会使它 看起来 就好像您可以将 boolean
作为类型 Object
的参数传递一样。
另一方面,如果将 boolean
替换为 Boolean
,它会编译,因为 Boolean
是 Object
的子类型。
问题在于
Object... params
要解决歧义 - 更改如下代码
打电话
public static <T> T make(String name, Class<T> parentClass,
boolean rethrowRuntimeExceptions,
Object... params) throws DLException
这样称呼它:
SimpleFactory.make(className, Object.class, false, new Object[]{one, two});
和
打电话给
public static <T> T make(String name, Class<T> parentClass,
Object... params) throws DLException
这样称呼它:
SimpleFactory.make(className, Object.class, new Object[]{false,one, two});