Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 7. Auflage |
<< | < | > | >> | API | Kapitel 6 - Ausdrücke |
Neben den bisher vorgestellten Operatoren stellt Java noch eine Reihe weiterer Operatoren zur Verfügung, die in diesem Abschnitt erläutert werden sollen.
Der Fragezeichenoperator ?: ist der einzige dreiwertige Operator in Java. Er erwartet einen logischen Ausdruck und zwei weitere Ausdrücke, die beide entweder numerisch, von einem Referenztyp oder vom Typ boolean sind.
Bei der Auswertung wird zunächst der Wert des logischen Operators ermittelt. Ist dieser wahr, so wird der erste der beiden anderen Operanden ausgewertet, sonst der zweite. Das Ergebnis des Ausdrucks a ? b : c ist also b, falls a wahr ist, und c, falls a falsch ist. Der Typ des Rückgabewerts entspricht dem Typ des größeren der beiden Ausdrücke b und c.
Ebenso wie in C gibt es auch in Java einen Type-Cast-Operator, mit dessen Hilfe explizite Typumwandlungen vorgenommen werden können. Der Ausdruck (type) a wandelt den Ausdruck a in einen Ausdruck vom Typ type um. Auch wenn a eine Variable ist, ist das Ergebnis von (type) a ein Ausdruck, der nicht mehr auf der linken, sondern nur noch auf der rechten Seite eines Zuweisungsoperators stehen darf.
Wie in Kapitel 5 erklärt, gibt es verschiedene Arten von Typkonvertierungen in Java. Mit Hilfe des Type-Cast-Operators dürfen alle legalen Typkonvertierungen vorgenommen werden. Der Type-Cast-Operator wird vor allem dann angewendet, wenn der Compiler keine impliziten Konvertierungen vornimmt; beispielsweise bei der Zuweisung von größeren an kleinere numerische Typen oder bei der Umwandlung von Objekttypen.
Es gibt in Java einige Ausdrücke und Operatoren, die mit Objekten arbeiten oder Objekte produzieren. Die meisten von ihnen können erst dann erläutert werden, wenn die entsprechenden Konzepte in späteren Kapiteln eingeführt wurden. Der Vollständigkeit halber sollen sie dennoch an dieser Stelle erwähnt werden. |
|
Der +-Operator kann nicht nur mit numerischen Operanden verwendet werden, sondern auch zur Verkettung von Strings. Ist wenigstens einer der beiden Operatoren in a + b ein String, so wird der gesamte Ausdruck als String-Verkettung ausgeführt. Hierzu wird gegebenenfalls zunächst der Nicht-String-Operand in einen String umgewandelt und anschließend mit dem anderen Operanden verkettet. Das Ergebnis der Operation ist wieder ein String, in dem beide Operanden hintereinander stehen.
In Java ist die Konvertierung in einen String für nahezu jeden Typ definiert. Bei primitiven Typen wird die Umwandlung vom Compiler und bei Referenztypen durch die Methode toString ausgeführt. Die String-Verkettung ist daher sehr universell zu verwenden und ermöglicht (beispielsweise zu Ausgabezwecken) eine sehr bequeme Zusammenfassung von Ausdrücken unterschiedlichen Typs. Ein typisches Beispiel für die Verwendung der String-Verkettung ist die Ausgabe von numerischen Ergebnissen auf dem Bildschirm: |
|
001 /* Listing0603.java */ 002 003 public class Listing0603 004 { 005 public static void main(String[] args) 006 { 007 int a = 5; 008 double x = 3.14; 009 010 System.out.println("a = " + a); 011 System.out.println("x = " + x); 012 } 013 } |
Listing0603.java |
Die Ausgabe des Programms lautet:
a = 5
x = 3.14
Etwas Vorsicht ist geboten, wenn sowohl String-Verkettung als auch Addition in einem Ausdruck verwendet werden sollen, da die in diesem Fall geltenden Vorrang- und Assoziativitätsregeln zu unerwarteten Ergebnissen führen können. Das folgende Programm gibt daher nicht 3 + 4 = 7, sondern 3 + 4 = 34 aus. |
|
001 /* Listing0604.java */ 002 003 public class Listing0604 004 { 005 public static void main(String[] args) 006 { 007 // Die +-Operatoren werden von innen nach außen und von 008 // links nach rechts ausgewertet 009 System.out.println("3 + 4 = " + 3 + 4); 010 } 011 } |
Listing0604.java |
Um das gewünschte Ergebnis zu erzielen, müsste der Teilausdruck 3 + 4 geklammert werden:
001 /* Listing0605.java */ 002 003 public class Listing0605 004 { 005 public static void main(String[] args) 006 { 007 // Die +-Operatoren werden von innen nach außen und von 008 // links nach rechts ausgewertet 009 System.out.println("3 + 4 = " + (3 + 4)); 010 } 011 } |
Listing0605.java |
Die Operatoren == und != können auch auf Objekte, also auf Referenztypen, angewendet werden. In diesem Fall ist zu beachten, dass dabei lediglich die Gleichheit oder Ungleichheit der Referenz getestet wird. Es wird also überprüft, ob die Objektzeiger auf ein und dasselbe Objekt zeigen, und nicht, ob die Objekte inhaltlich übereinstimmen. |
|
Ein einfaches Beispiel ist der Vergleich zweier Strings a und b, die beide den Inhalt »hallo« haben:
001 /* Listing0606.java */ 002 003 public class Listing0606 004 { 005 public static void main(String[] args) 006 { 007 String a = new String("hallo"); 008 String b = new String("hallo"); 009 System.out.println("a == b liefert " + (a == b)); 010 System.out.println("a != b liefert " + (a != b)); 011 } 012 } |
Listing0606.java |
Werden sie zur Laufzeit angelegt (wie in diesem Beispiel), liefert
das Programm das erwartete Ergebnis, denn a
und b sind Referenzen auf unterschiedliche
Objekte, also Zeiger auf unterschiedliche Instanzen derselben Klasse.
a == b liefert false
a != b liefert true
Das ist das erwartete Verhalten für fast alle Objektreferenzen. Werden die Strings als Literale dagegen zur Compile-Zeit angelegt und damit vom Compiler als konstant erkannt, sind sie genau dann Instanzen derselben Klasse, wenn sie tatsächlich inhaltlich gleich sind. Dies liegt daran, dass String-Literale mit Hilfe der Methode String.intern angelegt werden, die einen Puffer von String-Objekten verwaltet, in dem jede Zeichenkette nur einmal vorkommt. Wird ein bereits existierender String noch einmal angelegt, so findet die Methode den Doppelgänger und liefert einen Zeiger darauf zurück. Dieses Verhalten ist so nur bei Strings zu finden, andere Objekte besitzen keine konstanten Werte und keine literalen Darstellungen. Die korrekte Methode, Strings auf inhaltliche Übereinstimmung zu testen, besteht darin, die Methode equals der Klasse String aufzurufen (siehe Listing 6.7). |
|
001 /* Listing0607.java */ 002 003 public class Listing0607 004 { 005 public static void main(String[] args) 006 { 007 String a = new String("hallo"); 008 String b = new String("hallo"); 009 System.out.println("a.equals(b) liefert " + a.equals(b)); 010 } 011 } |
Listing0607.java |
Der instanceof-Operator kann verwendet werden, um herauszufinden, zu welcher Klasse ein bestimmtes Objekt gehört. Der Ausdruck a instanceof b liefert genau dann true, wenn a und b Referenztypen sind und a eine Instanz der Klasse b oder einer ihrer Unterklassen ist. Falls das Ergebnis des instanceof-Operators nicht bereits zur Compile-Zeit ermittelt werden kann, generiert der Java-Compiler Code, um den entsprechenden Check zur Laufzeit durchführen zu können.
In Java werden Objekte und Arrays mit Hilfe des new-Operators erzeugt. Sowohl das Erzeugen eines Arrays als auch das Erzeugen eines Objekts sind Ausdrücke, deren Rückgabewert das gerade erzeugte Objekt bzw. Array ist.
Der Zugriff auf Klassen- oder Instanzvariablen wird mit Hilfe des Punkt-Operators ausgeführt und hat die Form a.b. Dabei ist a der Name einer Klasse bzw. der Instanz einer Klasse und b ist der Name einer Klassen- oder Instanzvariable. Der Typ des Ausdrucks entspricht dem Typ der Variable und zurückgegeben wird der Inhalt dieser Variable.
In Java gibt es keine Funktionen, sondern nur Methoden. Der Unterschied zwischen beiden besteht darin, dass Methoden immer an eine Klasse oder die Instanz einer Klasse gebunden sind und nur in diesem Kontext aufgerufen werden können. Die Syntax des Methodenaufrufs gleicht der anderer Programmiersprachen und erfolgt in der (etwas vereinfachten) Form f() bzw. f(parameterliste). Der Typ des Ausdrucks entspricht dem vereinbarten Rückgabetyp der Methode. Der Wert des Ausdrucks ist der von der Methode mit Hilfe der return-Anweisung zurückgegebene Wert.
Methoden können selbstverständlich Nebeneffekte haben und werden in vielen Fällen ausschließlich zu diesem Zweck geschrieben. Ist dies der Fall, so sollte eine Methode als void deklariert werden und damit anzeigen, dass sie keinen Rückgabewert produziert. Die einzig sinnvolle Verwendung einer solchen Methode besteht darin, sie innerhalb einer Ausdrucksanweisung (siehe Kapitel 7) aufzurufen.
Da die Realisierung der Methodenaufrufe in Java recht kompliziert ist (die Sprachspezifikation widmet diesem Thema mehr als zehn Seiten), werden wir in Kapitel 8 noch einmal ausführlich darauf eingehen. |
|
Wie in anderen Programmiersprachen erfolgt auch in Java der Zugriff auf Array-Elemente mit Hilfe eckiger Klammern in der Form a[b] (bzw. a[b][c], a[b][c][d] usw. bei mehrdimensionalen Arrays). Dabei ist a der Name eines Arrays oder ein Ausdruck, der zu einem Array ausgewertet wird, und b ein Ausdruck, der zu einem int evaluiert werden kann. Der Typ des Ausdrucks entspricht dem Basistyp des Arrays, zurückgegeben wird der Inhalt des Array-Elements, das sich an Position b befindet. Wie in C und C++ beginnt die Zählung mit dem ersten Element bei Position 0.
Da es in Java keine expliziten Pointer gibt, fehlen auch die aus C bekannten Operatoren * zur Dereferenzierung eines Zeigers und & zur Bestimmung der Adresse einer Variablen. Des Weiteren fehlt ein sizeof-Operator, denn da alle Typen eine genau spezifizierte Länge haben, ist dieser überflüssig. Der Kommaoperator von C ist ebenfalls nicht vorhanden, er taucht aber als syntaktischer Bestandteil der for-Schleife wieder auf und erlaubt es, im Initialisierungsteil der Schleife mehr als eine Zuweisung vorzunehmen. |
|
Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 7. Auflage, Addison Wesley, Version 7.0 |
<< | < | > | >> | API | © 1998, 2011 Guido Krüger & Heiko Hansen, http://www.javabuch.de |