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:
//equals()
static boolean vergleiche(String s, String t){
return s.equals(t);
}
Die Punktnotation in der 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:
String[] hoererIn={
"Betty", "Frank", "Rafaela", "Torsten"};
System.out.println(
"HoererIn Nr. 2 heisst "+hoererIn[1]);
In Zeile 1 wird das Feld zugleich deklariert und allokiert. Das Feld
hat die Länge 4, seine Komponenten sind 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:
class 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
Achten Sie auf die rekursive Berechnung der Potenz
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]);
//BspA
double x;
System.out.println("x="+x);
Teil eines 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
//BspB
double[] x = new double[4];
System.out.println("x[0]="+x[0]);
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
//BspC
class BspC{
static double x;
static void main(String[] args){
System.out.println("x="+x);
}
}
an. Hier wird keine fehlende Initialisierung angemahnt. Diese wurde
automatisch vorgenommen, wie man an der Ausgabe x=0.0 erkennt.
Die Verwirrung wird größer in
//BspD
class BspD{
static String s;
static void main(String[] args){
System.out.println("s="+s);
}
}
Ausgabe ist s=null. Es scheint eine automatische
Initialisierung druch den "Null-String" gegeben zu haben - was auch
immer das ist.
Wir steigern uns:
//BspE
class BspE{
static double[] x;
static void main(String[] args){
System.out.println("x[0]="+x[0]);
}
}
Das Programm kann compiliert werden, erst das Laufen ergibt den
Laufzeitfehler java.lang.NullpointerException 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.