wird eine Variable namensString s="Java macht Freude"; System.out.println(s);
s
vom Typ einer Zeichenkette
deklariert und allokiert und danach ausgegeben. Wir wissen schon, dass
wir Zeichenketten mit dem Operator +
verketten können. Es gibt viele Methoden der Klasse
java.lang.String
, von denen wir - stellvertretend -
die Methode equals()
herausgreifen:
Die Punktnotation in der//equals() static boolean vergleiche(String s, String t){ return s.equals(t); }
return
-Zeile, die die
Methode equals()
an die Variable s
anheftet,
deutet darauf hin, dass equals()
eine Methode
der Klasse String
ist. Sie hat
einen Parameter des Typs String
und einen
Rückgabewert vom Typ boolean
. Jedes Objekt der
Klasse String
kann diese Methode einsetzen - mit Hilfe
der Punktnotation. Natürlich hätte man auch die
String
-Variable t
bitten können,
mittels t.equals(s)
zu klären, ob sie mit
s
identisch ist.
Will man Zahlen formatiert ausgeben, muss man die Zahlen als
Zeichenketten "behandeln": Mit double
x=Math.sin(1.3456);
wird aus dieser durch String
s=x+"";
eine Zeichenkette. Jetzt kann man z.B. mit
int j=s.indexOf(".");
die Position des Punktes herausfinden. Eine weitere String-Methode ist
String substring(int m, int
n)
, s.Aufgabe 9. So bewirkt z.B.
die Ausgabe "macht". Jetzt ahnt man, dass Zeichenketten Felder von Zeichen sein könnten, die bei 0 beginnend durchnummeriert (indiziert) sind - ein guter Übergang zum nächsten Abschnitt.String s="Java macht Freude"; System.out.println(s.substring(5,10));
Bemerkung: Es gibt eine Klasse StringBuffer, die in jeder Beziehung den
Charakter einer Klasse hat, weil Variable von diesem Typ reine
Referenzvariable sind, während bei Variablen vom Typ
String
der "Inhalt" der Variablen untrennbar mit der
Variablen verbunden ist.
HoererIn
, so kann
man mit HoererIn[j]
auf den Namen der HörerIn
Nr. j
zugreifen. Felder in Java erkennt man an den
eckigen Klammern. Das ganze kann so
(in einem main()
-Block) aussehen:
In Zeile 1 wird das Feld zugleich deklariert und allokiert. Das Feld hat die Länge 4, seine Komponenten sindString[] hoererIn={ "Betty", "Frank", "Rafaela", "Torsten"}; System.out.println( "HoererIn Nr. 2 heisst "+hoererIn[1]);
hoererIn[0],
hoererIn[1], hoererIn[2], hoererIn[3]
. Die Länge des
Feldes kann auch mit Hilfe von hoererIn.length
ermittelt
werden. An dieser Punktnotation erkennt man, dass Felder Objekte
sind. Dies wird erst recht deutlich, wenn man Felder allokiert, ohne
deren Komponenten schon festzulegen. Dies geschieht mit dem anfangs
kryptischen und gewöhnungsbedürftigen new-Operator:
Die erste Zeile ist die Deklaration, die zweite die Allokierung des Feldes. Dies kann auch wie bei den Grunddatentypen simultan geschehen:String[] hoererIn; hoererIn = new String[4]; hoererIn[0]="Betty"; ........
String[] hoererIn = new String[4]; hoererIn[0]="Betty"; ........
In der (Numerischen) Mathematik wimmelt es von
double
-Feldern, die auch Vektoren bei
eindimensionalen Feldern oder Matrizen bei zweidimensionalen
Feldern heißen.
Will man die Komponenten eines Vektors aufaddieren, kann dies mit folgender Methode geschehen:
double summe(double[] x){ double s=0; int n=x.length; for (int i=0;i<n;i++) s+=x[i]; return s; }//Ende summe()
Etwas komplizierter ist das folgende Beispiel: Eine kubische Funktion hat vier Koeffizienten, allgemein lautet ihre Abbildungsvorschrift f(x)=a0+a1*x+a2*x^2+a3*x^3. Es ist also naheliegend, die Koeffzienten durch ein Feld reeller Zahlen der Länge 4 innerhalb einer Methode zu erfassen:
Achten Sie auf die rekursive Berechnung der Potenzclass Feld1{ static double kubischeF(double[] a, double x){//Methode double y=0; double p=1; for (int i=0;i<4;i++) { y+=a[i]*p;//p=x^i p*=x; //p=x^{i+1} }//Ende for return y; }//Ende kubischeF() static void main(String[] args){ double[] a = {0.1, 2.3, -2, 4}; double x=0; while (x<2) { System.out.println(kubischeF(a,x)); x+=0.2; }//Ende while }//Ende main() }//Ende Feld1
x^i
innerhalb der Methode
kubischeF()
. Letztere besitzt
zwei Parameter (das Koeffizientenfeld und der Punkt, an dem
ausgewertet werden soll) und den Rückgabewert double
.
Die Länge des Feldes a
muss der Methode
kubischeF
nicht bekannt sein. Die Länge sollte aber
mindestens 4 sein! Ist sie kleiner, so kann das Programm erfolgreich
kompiliert werden, es gibt aber einen Laufzeitfehler mit der
Fehlermeldung java.lang.ArrayIndexOutOfBoundsException
.
Zweidimensionale Felder sind eindimensionale Felder,
deren Komponenten selbst wieder eindimensionale Felder sind. Man kann sich
eine rechteckige Tabelle vorstellen, bei denen man sich die Zeilen
indiziert vorstellt: a[j]
sei z.B. die j-te Zeile. Dann
ist a[j][k]
die k-te Komponente der j-ten Zeile. In der
Mathematik redet man von Matrizen. So kann eine Matrix mit 3
Zeilen und 4 Spalten folgendermaßen in einem Java-Programm
dargestellt werden:
double[][] a={{0.8, -0.7, 0.1, 2.1}, {9,0, -1, 2.2}, {-2, 1.1, 0, -8}}; System.out.println( "In Zeile 2 und Spalte 1 steht"+a[1][0]);
Teil eines//BspA double x; System.out.println("x="+x);
main()
-Blocks, so gibt es die
Compilerfehlermeldung x may not have been
initialized
. Hier wurde eine lokale Variable der Methode
main()
zwar deklariert, aber nicht initialisiert,
d.h. mit einem Inhalt versehen. Ganz entsprechende Fehlermeldungen
gibt es bei der Deklaration von Variablen anderer Typen wie
String s;
oder double[] x;
. In
jedoch wird das Feld gleichzeitig deklariert und initialisiert und den 4 Komponenten der Wert 0.0 zugewiesen. Die Verwendung des new-Operators dient also der Initialisierung. Ein bisschen anders sieht dies bei globalen Variablen aus. Fangen wir mit//BspB double[] x = new double[4]; System.out.println("x[0]="+x[0]);
an. Hier wird keine fehlende Initialisierung angemahnt. Diese wurde automatisch vorgenommen, wie man an der Ausgabe//BspC class BspC{ static double x; static void main(String[] args){ System.out.println("x="+x); } }
x=0.0
erkennt.
Die Verwirrung wird größer in
Ausgabe ist//BspD class BspD{ static String s; static void main(String[] args){ System.out.println("s="+s); } }
s=null
. Es scheint eine automatische
Initialisierung druch den "Null-String" gegeben zu haben - was auch
immer das ist.
Wir steigern uns:
Das Programm kann compiliert werden, erst das Laufen ergibt den Laufzeitfehler java.lang.NullpointerException//BspE class BspE{ static double[] x; static void main(String[] args){ System.out.println("x[0]="+x[0]); } }
static double[] x;
wird das
double-Feld x
nur deklariert, aber nicht
initialisiert. Der Laufzeitfehler hätte etwa mit gleichzeitiger
Initialisierung durch static
double[] x = new double[4];
vermieden werden können.
Initialisierung heißt, dass ein Speicherplatz für den Inhalt
der Variablen geschaffen wird. Bei der reinen Deklaration ist die
Länge des Feldes noch unbekannt, es gibt noch keinen Sinn
Speicherplatz zu reservieren. Nun ist das double-Feld x
in dem Sinn eine Zeigervariable,
dass diese auf den Speicherplatz des Inhalts zeigt. Solange die
Initialisierung noch nicht erfolgt ist, weiß die Zeigervariable
nicht, wohin sie zeigen soll, sie ist ein Nullpointer. Wird nun der Inhalt des
Speicherplatzes eines Nullpointers erfragt (wie in BspE), so gibt es
den obigen Laufzeitfehler.
Alle Variablen der Grunddatentypen sind keine Zeigervariablen. Bei
ihrer Deklaration wird gleichzeitig Speicherplatz geschaffen und ihr
Inhalt vorbesetzt (z.B. durch null). Dennoch gibt es auch bei diesen
zuweilen (z.B. bei Verwendung als lokale Variable) Compilerfehler, die
eine Initialisierung anmahnen (s. BspA). Feldvariable und alle Objekte
(Variable von Klassen) sind Zeigervariable. Das zu verstehen, ist
ausgesprochen hilfreich. Mehr dazu im nächsten Abschnitt ( Referenzvariable ).
Übrigens spricht man auch von Allokierung statt von Initialisierung.
String
-Variablen. Auch diese sind
Zeigervariable, der Null-String ist ein Null-Pointer -
warum, können Sie herausfinden, indem Sie etwa versuchen mit
Hilfe von s.length() die Länge
eines deklarierten, aber nicht initialisierten Strings zu
erfragen. Allerdings ist ihr "Inhalt" unlösbar verbunden mit
ihrer Deklaration: im nächsten Abschnitt werden Sie sehen, dass
eine String-Variable als Parameter einer Methode vieles mit einer
Variablen vom Grunddatentyp gemein haben. Das ist anders bei der
Klasse StringBuffer, die in diesem
Kurs nicht behandelt wird.