Где двусмысленность в этом вызове метода Java?

Я получаю "ссылку, чтобы сделать неоднозначную" ошибку компилятора, которую я не понимаю.

у меня есть эти два метода

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.

4 ответов


проблема заключается в

Object... params

при вызове SimpleFactory.make(className, Object.class, false, one, two); Java не будет знать, нужно ли вставлять " false "в логический объект и передавать его в качестве первого аргумента массива varargs" params " (Boolean extends Object) и использовать

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

или позвонить

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

поскольку эта подпись также может принимать логическое значение перед параметрами varargs.

следовательно, почему это неоднозначно, обе подписи метода применимы.


компилятор сначала пытается найти соответствующую подпись thst не включает автобоксинг / распаковку или вызов переменной arity. Вызов переменной arity - это вызов метода varargs путем передачи списка параметров в качестве последнего аргумента (в отличие от массива).

в вашем случае оба включают вызов переменной 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 by Boolean, он компилируется, потому что Boolean является подтипом Object.


Я думаю, это потому, что компилятор не знает, хотите ли вы, чтобы логический параметр был включен в params или нет. Я мог бы либо вызвать функцию с 4 параметрами и передать логическое значение в качестве 3-го параметра, либо вызвать функцию с 3 параметрами и добавить логическое значение в объект... парамы. Компилятор не знает, что делать из-за этой неоднозначности. Дайте мне знать, если вам нужна дополнительная информация


проблема заключается в

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});