Advanced Java Services | Variable Argumentlisten (Varargs ab 1.5) |
Mit der Version 5 bzw. 1.5 hat Java variable Argumentenlisten bei Methoden eingeführt. Damit wurde ein Feature installiert, das es bereits in C gibt, der Mutter aller modernen Programmiersprachen. Die Syntax und auch der Aufruf ist sehr einfach.
public static void varargs(int... x) { for(int i=0; i < x.length ; i++) System.out.println(x[i]); }
Drei Punkte nach dem (beliebigen) Datentyp und ein Bezeichner. Das war's. Im Rumpf wird dann verraten, welchen Typ die so bezeichnete Variable hat. Es handelt sich um den zur Deklaration in der Parameterliste passenden Arraytyp. Aufgerufen wird das Ganze folgendermaßen:
varargs(3, 4, 5, 6); // 1
oder so
int x = 5, y = 6, z = 17; varargs(3, x, 5, y, 6, z); // 1
Im Grunde nimmt der Compiler dem Programmierer nur eine Routinearbeit ab, denn hinter den drei Punkten steckt folgende Deklarationen:
public static void varargs(int[] x)
Allerdings muß bei der letzeren Deklaration der Entwickler eine Arrayvariable übergeben. Diese Arbeit nimmt ihm der Compiler bei einer varargs-Deklaration ab indem er beim Anruf der Methode ein anonymes Array on the fly erzeugt. Die Zeile
varargs(3, x, 5, y, 6, z);
übersetzt der Compiler zu
varargs( new int[] {3, x, 5, y, 6, z} );
Eine Folgerung aus dieser Tatsache ist natürlich, daß die beiden Deklarationen
public static void varargs(int... x)
und
public static void varargs(int[] x)
nicht beide zusammen existieren können, andernfalls meldet sich der Compiler mit der Meldung
cannot declare both varargs(int[]) and varargs(int...)
Beim Überladen von Methoden kann es zu Mehrdeutigkeiten kommen. In diesem Fall versucht der Compiler diese nach gewissen Regeln aufzulösen. Gelingt ihm das nicht, so meldet er einen Compilerfehler. Einen Fall von Mehrdeutigkeit haben wir im letzten Abschnitt festgestellt. In diesem Fall hat der Compiler die beiden Deklarationen als gleichwertig angesehen und konnte daher keine Entscheidung treffen. Es folgen einige Beispiele, bei denen der Compiler die Mehrdeutigkeiten auflösen kann.
public static void varargs1(int a, int b) // 1 { System.out.println("int, int"); } public static void varargs1(int... arr) // 2 { System.out.println("int..."); }
Aufruf
varargs2(7, 8);
Welche Methode wird aufgerufen?
public static void varargs2(double a, double b) // 3 { System.out.println("int, int"); } public static void varargs2(short... arr) // 4 { System.out.println("short..."); }
Aufruf
varargs2(7, 8);
Welche Methode wird aufgerufen?
public static void varargs3(Integer a, Integer b) // 5 { System.out.println("Integer, Integer"); } public static void varargs3(int... arr) // 6 { System.out.println("int..."); }
Aufruf
varargs2(7, 8);
Welche Methode wird aufgerufen?
Der Compiler entscheidet ein jedesmal konservativ. In keinem der drei Fälle wählt der Compiler die Variante mit Varargs. Im Beispiel 1 entscheidet sich der Compiler für althergebrachte Deklaration, im Beispeil 2 bevorzugt er ein Typkonvertierung zu double (Widening), im Beispiel 3 bevorzugt er Autoboxing. Diese Regeln lassen sich im Englischen sehr prägnant ausdrücken.