Java-Methodenparameter
Werte in Java-Methoden durch Parameter übergeben und den Unterschied zwischen Parametern und Argumenten verstehen.
Parameter sind die Eingaben, die eine Methode deklariert; Argumente sind die Werte, die Sie beim Aufruf übergeben. Der Compiler prüft, ob die Argumente nach Typ und Position mit den Parametern übereinstimmen, und übergibt sie dann als lokale Variablen, die die Methode in ihrem Rumpf verwenden kann.
Dieses Kapitel erläutert diese Übergabe im Detail — die Syntax, die Typen, die übergeben werden können, und die Regeln, die Java bei der Konvertierung anwendet.
Parameter deklarieren
Die Parameterliste einer Methode ist eine kommagetrennte Folge von Typ Name-Paaren:
public static void greet(String name, int times) {
for (int i = 0; i < times; i++) {
System.out.println("Hello, " + name);
}
}Eine Methode kann null, einen oder mehrere Parameter deklarieren. Jeder benötigt einen eigenen Typ — es gibt keine Kurzschreibweise wie int a, b (das wäre int a gefolgt von b, was nicht kompiliert).
Mit Argumenten aufrufen
An der Aufrufstelle übergeben Sie Werte in derselben Reihenfolge, in der die Parameter deklariert sind:
greet("Ada", 3); // name = "Ada", times = 3Der Compiler prüft zwei Dinge:
- Arität — die Anzahl der Argumente stimmt mit der Anzahl der Parameter überein.
- Typen — der Typ jedes Arguments ist mit dem Typ des entsprechenden Parameters kompatibel.
Schlägt eine der Prüfungen fehl, wird das Programm nicht kompiliert. Übergeben Sie einen String, wo ein int erwartet wird, erhalten Sie einen Fehler wie incompatible types: String cannot be converted to int.
Parameter sind lokale Variablen
Innerhalb der Methode verhält sich jeder Parameter wie eine lokale Variable, die mit dem Argumentwert initialisiert wurde:
public static int doubleIt(int n) {
n = n * 2; // legal: n is just a local
return n;
}
int x = 5;
int result = doubleIt(x); // result is 10
System.out.println(x); // still 5Die Neuzuweisung von n innerhalb von doubleIt wirkt sich nicht auf x an der Aufrufstelle aus. Jeder Aufruf erhält seine eigene frische Kopie des Parameters. Das ist gemeint, wenn man sagt, Java arbeitet nach dem Prinzip „Pass-by-Value" — jedes Argument wird in den Parameterslot kopiert. Die nächsten Kapitel behandeln die Konsequenzen, insbesondere für Objekt-Argumente.
Implizite Erweiterung (Widening)
Java erweitert automatisch einen kleineren numerischen Typ auf einen größeren, um mit dem Parameter übereinzustimmen:
public static double half(double x) {
return x / 2;
}
int n = 7;
double result = half(n); // n is widened from int to doubleErweiterung ist erlaubt, weil dabei keine Information verloren geht. Verengung (Narrowing) ist nicht implizit — um einen double an einen int-Parameter zu übergeben, ist ein Cast erforderlich:
half(7.5); // fine: double argument, double parameter
double d = 3.7;
int i = (int) d; // explicit cast
half(i); // also fineEs gelten dieselben Erweiterungsregeln wie bei der Zuweisung: byte → short → int → long → float → double und char → int.
Objekt-Parameter
Sie können jedes Objekt — String, ein Array, eine benutzerdefinierte Klasse — übergeben, indem Sie einen Parameter des entsprechenden Referenztyps deklarieren:
public static int firstLength(String[] words) {
if (words.length == 0) return 0;
return words[0].length();
}
String[] colors = {"red", "green", "blue"};
System.out.println(firstLength(colors)); // 3Das Argument kann auch null sein; in diesem Fall ist der Parameter null, und jeder Feldzugriff oder Methodenaufruf darauf wirft eine NullPointerException. Methoden, die Referenzen akzeptieren, prüfen dies in der Regel vorab oder dokumentieren, dass null nicht erlaubt ist.
null übergeben
null ist mit jedem Referenztyp zuweisungskompatibel, daher kann es für jeden Objekt-Parameter übergeben werden:
greet(null, 1);Dereferenziert die Methode den Parameter (name.length(), name.charAt(0), …), wirft sie eine Ausnahme. Eine defensive Methode behandelt null explizit, oft mit einer Prüfung am Anfang:
public static void greet(String name, int times) {
if (name == null) name = "stranger";
for (int i = 0; i < times; i++) {
System.out.println("Hello, " + name);
}
}Finale Parameter
Sie können einen Parameter mit final markieren, um die Neuzuweisung innerhalb der Methode zu verbieten:
public static int doubleIt(final int n) {
// n = n * 2; // ERROR: cannot assign a value to final variable n
return n * 2;
}Das ändert nichts daran, was der Aufrufer sieht — nur ob der Methodenrumpf den Parameterslot wiederverwenden darf. Viele Styleguides behandeln alle Parameter so, als wären sie final, auch ohne das Schlüsselwort; berechnen Sie einfach neue Werte, anstatt den Parameter zu verändern.
Reihenfolge der Argumentauswertung
Wenn Sie f(a(), b(), c()) schreiben, werden die Argumente von links nach rechts ausgewertet, alle bevor f aufgerufen wird. Wenn a() eine Ausnahme wirft, werden b() und c() nie ausgeführt.
public static int log(String label, int value) {
System.out.println(label + " = " + value);
return value;
}
public static int sum(int a, int b, int c) {
return a + b + c;
}
sum(log("a", 1), log("b", 2), log("c", 3));
// prints:
// a = 1
// b = 2
// c = 3Diese Determiniertheit unterscheidet Java von C und C++; in Java ist die Reihenfolge fest und vorhersehbar.
Ein vollständiges Beispiel
Wie geht es weiter?
Sie wissen nun, wie Daten in eine Methode gelangen. Manchmal möchten Sie zwei Methoden mit demselben Namen, aber unterschiedlichen Eingaben — beispielsweise eine, die einen int akzeptiert, und eine andere, die einen String akzeptiert. Java erlaubt Ihnen, beide gleichzeitig mit Methodenüberladung zu schreiben.