5. Methoden (Teil 3)lokale und globale Variable, Zeigervariable, Call by value, call by referenceMethoden können keinen, einen oder mehrere Parameter besitzen. Die Datentypen der Parameter müssen angegeben werden. Der Methodenblock selbst kann neue (lokale) Variable deklarieren und initialisieren. In ihm kann aber auch auf (globale) Variable der jeweiligen Klasse zurückgegriffen werden. Es ist zum Verständnis insbesondere von Programmen mit OOP ganz wesentlich zu verstehen, was intern mit diesen Variablen geschieht. 5.1 Lokale und globale VariableMan betrachte die folgende Methode mit einem static double mittelwert(double[] x){ int i, n; n=x.length; double w=0; for (i=0;i<n;i++) w+=x[i]; w/=n; return w; }//Ende mittelwert()
(Globale) Variable der Applikationsklasse (diese müssen
als class MW{ static double v, w; static double mittelwert(double[] x){ int i, n; n=x.length; double w=0; for (i=0;i<n;i++) w+=x[i]; w/=n; return w; //w=berechneter Mittelwert }//Ende mittelwert() public static void main(String[] args){ double[] y={1, 2.1, 3}; w=y[0]; //hat nichts mit dem Mittelwert zu tun v=mittelwert(y); //Hier wird der Mittelwert mit v bezeichnet System.out.println("w="+w+" Mittelwert="+v); //Ausgabe: w=1.0 Mittelwert=2.033333333333333 }//Ende main() }//Ende class MW Wir verwenden hier unnötiger Weise eine globale und eine lokale Variable
gleichen Namens Globale Variable können aber sehr wohl in einem Methodenblock verändert werden, wenn es keine lokalen Variablen gleichen Namens gibt. Denselben Zweck wie das letzte Programm erfüllt class MW2{ static double w;//global static void mittelwert(double[] x){ int i, n; n=x.length; for (i=0;i<n;i++) w+=x[i]; w/=n; }//Ende mittelwert() public static void main(String[] args){ double[] y={1, 2.1, 3}; mittelwert(y); System.out.println("Mittelwert="+w); //Ausgabe: Mittelwert=2.033333333333333 }//Ende main() }//Ende class MW2 Dieses Programm ist sogar kürzer, aber weniger gut
strukturiert. Der Mittelwert wird jetzt implizit berechnet, die
Methode Übrigens hätte die lokale Feldvariable 5.2 Zeigervariable, call by value, call by reference, ReferenzvariableMan wiederhole zunächst Deklaration und Initialisierung. Wir starten mit dem folgenden Programm: class lokal{ static void lift(double x){ x+=5; } public static void main(String[] args){ double y=1; lift(y); System.out.println(y); //Ergebis: 1, nicht 6 } } Jetzt machen wir Gleiches mit Zeichenketten und Feldern: class lokal{ static void lift(double x){ x+=5; } static void lift(String s){ s+=" !!!!"; } static void lift(double[] x){ for (int i=0;i<x.length;i++) x[i]+=5; } public static void main(String[] args){ double y=1; lift(y); System.out.println(y); String s="Java"; lift(s); System.out.println(s); double[] z={1,2,3}; lift(z); for(int i=0;i<3;i++) System.out.println(z[i]); } } Nur bei dem
Jetzt wenden wir uns den Parametern einer Methode genauer zu wie dem
Parameter
Der invertierte Vektor ist hier der Rückgabewert der Methode
Alternativ kann man auch versuchen, keinen
Rückgabewert vorzusehen und den Parameter class KopfFuss2{ static void umkehren(double[] x){ int i, n; n=x.length; double[] w=new double[n]; // x und w sind lokale Variable dieser Methode for (i=0;i<n;i++) w[i]=x[n-i-1]; x=w; //bleibt ohne Wirkung nach außen! }//Ende umkehren() public static void main(String[] args){ double[] y={1, 2.1, 3}; umkehren(y); //tut nicht, was es soll! for (int i=0;i<3;i++) System.out.println(y[i]); }//Ende main() }//Ende class KopfFuss2 Dies klappt in dem Sinne nicht, dass die Anweisung umkehren(y);
gar keine Umkehr bewirkt! Der Inhalt der lokalen Um die Verwirrung zu vergrößern: Das Programm class KopfFuss3{ static void umkehren(double[] x){ int i, n; n=x.length; double[] w=new double[n]; for (i=0;i<n;i++) w[i]=x[n-i-1]; for (i=0; i<n;i++) x[i]=w[i]; }//Ende umkehren() static void main(String[] args){ double[] y={1, 2.1, 3}; umkehren(y); for (int i=0;i<3;i++) System.out.println(y[i]); }//Ende main() }//Ende class KopfFuss3 leistet das, was es soll! Offensichtlich sind die beiden Zeilen
Grundsätzlich werden Methodenparameter beim Aufruf einer Methode stets kopiert, sie werden zu einem lokalen Parameter der Methode. Nach Beendigung der Methode wird die Kopie wieder gelöscht. Bei Feldern (wie auch bei anderen Objekten) sind die zugehörigen Variablen jedoch Zeigervariable. Ich wiederhole (s. auch Kap.4.3): Das muss man sich so vorstellen, dass eine solche Variable ihren Bezeichner abspeichert und als Information den Ort des Speicherplatzes enthält, wo das Objekt (hier das gesamte Feld, sein Inhalt) abgespeichert wird. Die Variable zeigt also nur auf den Ort des eigentlichen Inhalts. Die Zeigervariable beansprucht vergleichsweise wenig Speicher im Gegensatz zu dem (vielleicht sehr langen) Feld. Beim Aufruf von Anders in der Klasse Das Anlegen einer Kopie der beim Aufruf der Methode verwendeten Methodenparameter wird mit call by value bezeichnet, während ein call by reference es ermöglicht, eine Veränderung des Parameters innerhalb des Methodenblocks zu bewirken, die auch nach Beendigung der Methode wirksam bleibt. Sind Parameter einer Methode Zeigervariable, so ist es trotz des call by value-Prinzips möglich, die Inhalte der Speicherbereiche, auf die der Zeiger zeigt, zu verändern. Die Wirkung der Methode ist dann - was den Inhalt betrifft - identisch mit einer Call by reference-Wirkung. Man nennt daher Zeigervariable auch Referenzvariable. Im Gegensatz zu C++ "verschleiert" Java die Tatsache, dass alle Objektvariable (Sie kennen bisher nur Felder!) Zeigervariable sind. Dadurch bleibt der unerfahrenen ProgrammiererIn manche Wirkung kryptisch, z.B. die Fehlermeldung java.lang.NullpointerException. Variable vom Grunddatentyp sind keine Zeigervariable, sie sind unauflöslich mit ihrem Inhalt verbunden. Treten sie als Parameter einer Methode auf, wird stets eine Kopie angelegt und alle Änderungen betreffen nur die Kopie, niemals die Variable, die an die Methode übergeben wurde. So bleibt die folgende Methode, obwohl syntaktisch richtig, wirkungslos:
Es gibt im Gegensatz anderer Programmiersprachen wie Pascal und C keine einfache Möglichkeit, Variable eines Grunddatentyps als Referenzvariable zu behandeln. Vor einem Jahr hatte ich einen Preis für ein einfaches Vertausche-Programm ausgesetzt - ohne Ergebnis. Im Gegensatz zu Variablen vom Grunddatentyp können die Inhalte von Objektvariablen leicht vertauscht werden: class VertauscheFelder{ static void vertausche(double[] x, double[] y){ int n=x.length; for (int i=0;i<n;i++){ double h=x[i]; x[i]=y[i]; y[i]=h; } }//Ende vertausche() public static void main(String[] args){ double[] x={1,2}; double[] y={-1,-2}; vertausche(x,y); System.out.println("x(0]="+x[0]+" x[1]="+x[1]); }//Ende main() }//Ende class Einen letzten Satz zu String-Variablen. Man kann durch sie eine NullPointerException hervorrufen, was auf den Zeigercharakter hinweist. Was jedoch ihre Verwendung als Paramter von Methoden betrifft, ähneln sie eher den Grunddatentypen: es wird eine Kopie auch des Inhalts angelegt, d.h. (Zeiger-)Variable und Inhalt sind nicht zu trennen (anders bei der Klasse StringBuffer. Dieser Abschnitt ist für ProgrammieranfängerInnen nicht einfach. Also nicht verzagen, wenn Sie ihn nicht auf Anhieb verstehen. Es wird noch viele Gelegenheiten geben, auf das Phänomen Zeiger- oder Referenzvariable hinzuweisen. 5.3 Überladen von MethodenJava erlaubt es verschiedene Methoden gleichen Namens zu verwenden, sofern sie sich im Typ des Rückgabewertes nicht unterscheiden. Sie unterscheiden sich nur in ihren Parametern (Anzahl oder Typ). Nehmen wir an, wir wollen mit Hilfe einer Methode die //Wurzel static double wurzel(double x){ return Math.sqrt(x); }//Ende 1 static double wurzel(double x, int p){ return Math.pow(x,(double) 1/p);//Casting!! }//Ende 2 Jetzt kann die Methode Weiter mit 6. Datenein- und -ausgabe, Fehlerbehandlung
|
![]() ![]() |
Impressum | 2009-03-14, wwwmath (WL) |