Where is the ambiguity in this call to Java?

I get an error "link to make is twoiguous", which I do not understand.

I have two methods

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 

This line of code is marked mixed

  String className = "clsNme"; String one = "1"; String two = "2"; SimpleFactory.make(className, Object.class, false, one, two); 

Here is the error

 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...) 

Does the presence of a logical parameter mean the first method of a closer match than the second?

If that matters, this is part of the PowerMock test. Here is the complete method

 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 

}

If this helps: I use javac 1.8.0_77, Mokito 1.10.19 and Powermock 1.6.3.

+6
source share
4 answers

The challenge lies in

 Object... params 

When calling SimpleFactory.make(className, Object.class, false, one, two); Java will not know whether to insert "false" in the Boolean object and pass it as the first argument to the varargs "params" (Boolean extends Object) array and use

 make(String name, Class<T> parentClass, Object... params) 

or call

 make(String name, Class<T> parentClass, boolean rethrowRuntimeExceptions, Object... params) 

since this signature can also take a boolean before varargs parameters.

Therefore, why this is ambiguous, both method signatures are applicable.

+5
source

First, the compiler tries to find a suitable signature that does not include autoboxing / unpacking or calling the arity variable. The call to the arity variable is when you call the varargs method, passing a list of parameters as the last argument (as opposed to an array).

In your case, both include calling the arity variable. When this happens, the most specific overload is selected. For your situation, none of them are considered more specific, as defined in JLS. This is because none of the boolean and Object types is a subtype of the other.

Simplifying your example is a bit, the following does not compile.

 static void foo(boolean b, Object... arr) { } static void foo(Object... arr) { } public static void main(String[] args) { foo(true); } 

The first version will not accept any arguments of type Object , and the second will not accept any arguments of type boolean . Therefore, it is not more specific. (Auto-boxing only makes it look like you can pass boolean as an argument of type Object ).

On the other hand, if you replace boolean with boolean , it will compile because boolean is a subtype of Object .

+6
source

I think this is because the compiler does not know if you want to include the boolean parameter in params or not. I could call a function with 4 parameters and pass a boolean as the 3rd parameter, or call a function with three parameters and add a boolean to the Object parameters .... The compiler does not know what to do because of this ambiguity. Let me know if you need more information.

+1
source

The challenge lies with

 Object... params 

To eliminate the ambiguity, change the code as shown below

To call

 public static <T> T make(String name, Class<T> parentClass, boolean rethrowRuntimeExceptions, Object... params) throws DLException 

name it as follows:

  SimpleFactory.make(className, Object.class, false, new Object[]{one, two}); 

and

To call

  public static <T> T make(String name, Class<T> parentClass, Object... params) throws DLException 

name it as follows:

  SimpleFactory.make(className, Object.class, new Object[]{false,one, two}); 
+1
source

All Articles