Где же двусмысленность в этом вызове метода 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 6

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.

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

Компилятор сначала пытается найти соответствующую сигнатуру, которая не включает автобоксинг / распаковку иливызов переменной 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 по 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});