2016-04-03 7 views
6

Ich bekomme einen "Verweis zu machen ist mehrdeutig" Compiler-Fehler, den ich nicht verstehe.Wo ist die Mehrdeutigkeit in dieser Java-Methode Aufruf?

Ich habe diese beiden Methoden

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 

Diese Codezeile als nicht eindeutig gekennzeichnet wird

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

Hier ist der Fehler

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

nicht das Vorhandensein der Does Boolescher Parameter macht die erste Methode näher als die zweite?

Wenn es darauf ankommt, ist dies Teil eines PowerMock Test Dies ist die komplette Methode

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 

}

Wenn es hilft: Ich bin mit javac 1.8.0_77, Mokito 1.10.19, und Powermock 1.6.3.

+0

Basierend auf den Lösungen unten, sprach ich die Compiler-Fehler, die durch die 'boolean' Parameter' Boolean' ändern. Dies bedeutet, dass Benutzer 'Boolean.TRUE' anstelle von' true' übergeben müssen; aber das scheint weniger anstößig zu sein, als dass sie 'new Object [] {a, b, c} eingeben' – Zack

Antwort

5

Das Problem liegt in

Object... params 

Beim Aufruf SimpleFactory.make(className, Object.class, false, one, two); Java wird nicht wissen, ob die "false" in ein Boolean-Objekt Feld und es als erstes Argument des "params" pass varargs Array (Boolean nennen erstreckt Objekt) und

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

oder ob verwenden

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

da diese Signatur auch einen Boolean akzeptieren kann, bevor die Params varargs.

Daher, warum es zweideutig ist, sind beide Methodensignaturen anwendbar.

+0

Ich denke, es ist erwähnenswert, dass die Ambiguität kommt, weil Java varargs und autoboxing gleichermaßen bewertet. Die meisten von uns würden die Verwendung eines literalen Booleschen Wertes erwarten, um Wahl 1 über eine bessere Übereinstimmung zu stellen; aber da das Autoboxing auf der gleichen "Ebene" ist, wird Java nicht wählen. – Zack

+0

Das ist eine schlechte Wahl IMO. Der Aufruf mit dem booleschen Wert sollte bevorzugt werden. – Vincent

1

Ich denke, es ist, weil der Compiler nicht weiß, ob der boolesche Parameter in params enthalten sein soll oder nicht. Ich könnte entweder die Funktion mit 4 Parametern aufrufen und den Booleschen Wert als 3. Parameter übergeben, oder ich könnte die Funktion mit 3 Parametern aufrufen und den Booleschen Wert zu den Objektparametern hinzufügen. Der Compiler weiß aufgrund dieser Mehrdeutigkeit nicht, was zu tun ist. Lassen Sie mich wissen, wenn Sie weitere Informationen benötigen

6

Der Compiler versucht zuerst, eine passende Signatur zu finden, die nicht Autoboxing/Unboxing oder Variable Arity Invocation enthält. Der Aufruf variabler Variablen erfolgt, wenn Sie eine varargs-Methode aufrufen, indem Sie eine Parameterliste als letztes Argument übergeben (im Gegensatz zu einem Array).

In Ihrem Fall beinhalten beide einen variablen Arity-Aufruf. Wenn dies geschieht, wird die spezifischste Überladung gewählt. Für Ihre Situation wird keiner als spezifischer betrachtet, wie in der JLS definiert. Dies liegt im Wesentlichen daran, dass keiner der Typen boolean und Object ein Untertyp des anderen ist.

Vereinfacht Ihr Beispiel ein wenig, kompiliert das folgende nicht.

static void foo(boolean b, Object... arr) { 

} 

static void foo(Object... arr) { 

} 

public static void main(String[] args) { 
    foo(true); 
} 

Die erste Version wird kein einziges Argument vom Typ akzeptieren Object und die zweite wird nicht ein einziges Argument vom Typ boolean akzeptieren. Daher ist keiner spezifischer. (Autoboxing macht es nur aussehen, als ob Sie eine boolean als Argument des Typs Object übergeben können).

Auf der anderen Seite, wenn Sie boolean durch ersetzen, kompiliert es, weil ein Untertyp von Object ist.

+0

Diese Antwort erklärt nicht, warum 'make (String Class , boolean, Object ...)' nicht für 'make (className, Object.class, false, one, two)' ausgewählt wird, da dies der Fall wäre der spezifischste. Und OPs Code funktioniert gut für mich. – Tom

+0

@Tom Ich weiß nicht, was du meinst. Meine Antwort erklärt, warum keiner spezifischer ist, oder? Wenn der Code für Sie kompiliert, ist es ein Compilerfehler. –

+0

@Tom http://ideone.com/cAGsYR –

1

Problem liegt bei

Object... params 

die Mehrdeutigkeit zu beheben - unter

den Code wie

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

es so nennen nennen ändern:

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

Und

Um

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

Anruf es so zu nennen:

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

@Tom: Danke für den Fang. Der Beitrag wurde aktualisiert. – Sanj

+1

Das funktioniert; Die Absicht der varargs besteht jedoch darin, die Methoden für die Benutzer einfacher zu machen. Die Varargs müssen diesen Zweck besiegen. In meinem Fall hat das Ändern von "boolean" zu "Boolean" das Problem mit weniger "extra typing" behoben – Zack

Verwandte Themen