/ / Der Methodenaufruf ist mit dem Operator varargs ambig - Java, Methodenüberladung, Variadic-Funktionen, Scjp

Methodenaufruf ist nicht eindeutig mit Varargs-Operator - Java, Methodenüberladung, Variadic-Funktionen, Scjp

Der folgende Code erzeugt den Syntaxfehler:

Die Methode f(int[]) ist für den Typ C mehrdeutig

Mein Code:

public class C{

public static void f(int... i)
{
System.out.println("a");
}

public static void f(Integer... i)
{
System.out.println("b");
}

public static void main(String[] args) {
f(new Integer(2));
}
}

Wenn ich Array-Notation verwende [] anstatt der ... und rufen Sie die Funktion korrekt mit auf f(new Integer[]{3,4,5})kann der Compiler richtig entscheiden, welche Methode ich verwenden möchte.

Aus welchem ​​Grund kann der Compiler nicht entscheiden, mit welcher Funktion er aufgerufen wird ...?

Antworten:

2 für die Antwort № 1

Die Suche nach der "richtigen" Methode für eine bestimmte Aufrufstelle wird in beschrieben JLS, Abschnitt 15.12, "Methodenaufrufausdrücke". Nach einem kurzen Vorspiel mit grundlegenden Sanitätsprüfungen beginnt der relevante Teil bei Abschnitt 15.12.2.1, Identifizieren potenziell anwendbarer Methoden. In Ihrem Fall sind beide Methoden möglicherweise anwendbarnach dieser Definition.

Der nachfolgende Prozess besteht aus drei Phasen. In Ihrem Fall ist die Methode a variable arity Methode (aufgrund der "varargs"). So fängt es gleich bei an 15.12.2.4, Phase 3: Identifizieren Sie die anwendbaren Methoden der variablen Arität.

Die Methode m ist genau dann eine anwendbare Variable-Arity-Methode, wenn alle der folgenden Bedingungen erfüllt sind:

  • Für 1 ≤ i <n kann der Typ von ei, Ai, durch Methodenaufruf-Umwandlung in Si umgewandelt werden.
  • ...

(die anderen Bedingungen sind hier nicht relevant)

Das Methodenaufrufkonvertierung (JLS, 5.3) erlaubt folgende Konvertierungen:

  • eine Identitätsumwandlung (§5.1.1)
  • eine sich erweiternde primitive Konvertierung (§5.1.2)
  • eine erweiterte Referenzumrechnung (§5.1.5)
  • eine Boxkonvertierung (§5.1.7), optional gefolgt von einer erweiterten Referenzkonvertierung
  • eine Unboxing-Konvertierung (§ 5.1.8), optional gefolgt von einer sich erweiternden primitiven Konvertierung

Die Umwandlung von Integer zu Integer ist eine Identitätsumwandlung (erster Aufzählungspunkt). Die Umwandlung von Integer zu int ist eine Unboxing-Konvertierung (letzter Aufzählungspunkt).

Beide Methoden sind also "anwendbare Variable-Arity-Methoden" gemäß der Spezifikation.


0 für die Antwort № 2

Varargs und Boxing wurden beide ab Java 5 eingeführt.Bei Java 5 kam es zu Problemen mit dem Umgang mit veraltetem Code, bei dem der Compiler eine Verbreitungsoperation ausgeführt hat (z. B. wenn es lang ist, wählt der Compiler lang Integer, da die Erweiterung von int auf long vor Java 5 zulässig war), aber da varargs und Boxing befindet sich auf derselben Ebene (Java 5 und höher). Der Compiler kann den korrekten Typ nicht ermitteln

Es gibt keine definierte Präferenz zwischen Varargs und Boxen / Unboxing, wenn sie in Kombination verwendet werden


0 für die Antwort № 3

Die Regel ist WBV/WAV Verbreiterung -> (Auto) Boxen -> Varargs im Falle von Überladen der Methode.

  1. Erweiterung

    int -> long -> float -> double
    
  2. Boxen

    Integer -> Number -> Object
    
  3. a) Verbreiterung dann Varargs

    int... -> long... -> float... -> double...
    

    b) Boxen dann Varargs

    Integer... -> Number... -> Object...
    

In anderen Worten

   Varargs  [Last option]
^
|
Boxing   [Newer style, added in Java 1.5]
^
|
Widening [Older style, choosen by the compiler to support existing code]

Hinweis:

  • Boxing dann Widening ist auch erlaubt.
  • Varargs dann Boxing ist nicht erlaubt.
  • Varargs wird als letzte Option zwischen behandelt Widening und boxing
  • Wählt entweder Widening then Varargs oder Boxing then Varargs. Wenn beide Möglichkeiten vorhanden sind, ergibt sich daraus mehrdeutig Methodenaufruf.

Die Konvertierung in Ihrem Fall von f(new Integer(2)). Wie in der Regel Boxing dann Widening

Integer -> Number -> Object -> int -> long -> float -> double

Nun gibt es 2 Möglichkeiten neben double

  • 3.a) Verbreiterung dann Varargs (int...)

  • 3.b) Boxen dann Varargs (Integer...)

aber beide sind anwesend und führen zu mehrdeutig Methodenaufruf.


Die Konvertierung in Ihrem Fall von f(new Integer[]{3,4,5})

Integer... ist direkte Übereinstimmung. Varargs dann Boxing ist nicht erlaubt.


-2 für die Antwort № 4

Das ... ist für eine variable Anzahl von Argumenten gedacht. Sie müssen die Werte wie f (1, 2, 3) übergeben.