Programmieren in Java: Einführung


Kapitel 7: Operatoren


Inhaltsverzeichnis

Dieses Buch ist unter einer Creative Commons-Lizenz lizensiert.


7.1 Allgemeines

Beschreibung

In den Kapiteln bisher haben Sie viel mit Klassen, Eigenschaften und Methoden gearbeitet. Sie sollten jedoch nicht vergessen, dass es wie in Kapitel 3 vorgestellt auch primitive Datentypen in Java gibt. Zu diesen zählen boolean, char, byte, short, int, long, float und double. Variablen von diesen Typen sind keine Referenzvariablen, zeigen auf keine Objekte und besitzen daher auch keine Eigenschaften und Methoden. Wie kann dann aber mit diesen Variablen überhaupt gearbeitet werden?

Java bietet wie jede Programmiersprache eine ganze Reihe an Operatoren an. Operatoren sind Zeichen mit einer speziellen Bedeutung, die sich auf ein, zwei oder drei Variablen anwenden lassen und die Informationen in den Variablen auf eine vordefinierte Weise verarbeiten. Operatoren, die genau eine Variable erfordern, heißen unäre Operatoren. Operatoren, die genau zwei Variablen erwarten, heißen binäre Operatoren. Der einzige Operator in Java, der drei Variablen erwartet und tertiärer Operator genannt wird, ist der Bedingungsoperator. Ein Beispiel für einen unären Operator ist das Minus-Zeichen, das das Vorzeichen einer Zahl einfach umdreht. Das Mal-Zeichen, um Zahlen zu multiplizieren, ist hingegen ein binärer Operator, da in jedem Fall zwei Variablen oder zwei Werte benötigt werden.

In Java stehen etwa 40 Operatoren zur Verfügung. Sie lassen sich in folgende Gruppen einteilen: Arithmetische Operatoren ermöglichen die Ausführung der Grundrechenarten in Java. Über Vergleichsoperatoren können Werte in Variablen verglichen werden. Während arithmetische Operatoren die Verarbeitung von Zahlen unterstützen, stehen logische Operatoren zur Verfügung, um mit Wahrheitswerten wie true und false zu rechnen. Bitweise Operatoren erlauben das Setzen und Löschen einzelner Bits, werden aufgrund der Komplexität und des notwendigen tiefergehenden Verständnisses in diesem Buch nicht behandelt. Über Zuweisungsoperatoren können Werte in anderen Variablen gespeichert werden.


7.2 Arithmetische Operatoren

Grundrechenarten

Um die vier Grundrechenarten Addition, Subtraktion, Multiplikation und Division in Java auszuführen, stehen die Operatoren +, -, * und / zur Verfügung. Es handelt sich hierbei um binäre Operatoren mit der Ausnahme, dass das Minus-Zeichen auch auf nur einen Operanden angewendet werden kann und dann das Vorzeichen umdreht.

Der Modulo-Operator % zählt ebenfalls zu den arithmetischen Operatoren. Er führt wie das / eine Division aus, gibt als Ergebnis jedoch den ganzzahligen Restwert zurück.

Betrachten Sie folgende Beispiele, um sich den Einsatz arithmetischer Operatoren zu verdeutlichen.

int i = 10, j = 5, r; 

r = i + j; 
r = i - j; 
r = i * j; 
r = i / j; 
r = i % j; 
r = -i; 

Wie Sie sehen erwarten alle Operatoren auf beiden Seiten des Operators eine Variable. Es handelt sich also jedesmal um binäre Operatoren. Das Minus-Zeichen stellt die Ausnahme dar: Wird es vor eine Variable gestellt, ohne linksseitig vom Operator eine andere Variable anzugeben, ist das Minus-Zeichen ein unärer Operator und dreht wie aus der Mathematik gewohnt das Vorzeichen des Operanden um.

Arithmetische Operatoren können auf Variablen primitiver Datentypen angewendet werden, die Zahlen speichern können. Das Ergebnis eines arithmetischen Operators ist seinerseits auch wieder eine Zahl.

Beachten Sie, dass arithemtische Operatoren nicht den Wert einer Variablen selber verändern. Sie führen eine Informationsverarbeitung durch, dessen Ergebnis erst in einer Variablen gespeichert werden muss, damit es nachfolgend im Programm zur Verfügung steht. Auch das Minus-Zeichen als unärer Operator dreht nicht das Vorzeichen des Wertes im Operanden selber um. Es wird vielmehr eine Information ähnlich wie bei Methoden zurückgegeben, die nun ein umgedrehtes Vorzeichen besitzt und erst wieder in einer Variablen gespeichert werden muss, um weiterverwendet werden zu können.


7.3 Vergleichsoperatoren

Werte vergleichen

Über Vergleichsoperatoren kann überprüft werden, ob ein Wert gleich, ungleich, größer, größer gleich, kleiner oder kleiner gleich einem anderen Wert ist. Für einen Vergleich werden logischerweise immer zwei Werte benötigt, so dass alle Vergleichsoperatoren binäre Operatoren sind. Folgende Zeichen stehen in Java als Vergleichoperatoren zur Verfügung: ==, !=, >, >=, < und <=.

Das Ergebnis eines Vergleiches ist entweder true oder false - also ein Wahrheitswert. Dies ist insofern nachvollziehbar, als dass ein Vergleich wahr ist oder eben nicht. Betrachten Sie nachfolgende Beispiele.

int i = 10, j = 5; 
boolean r; 

r = i == j; 
r = i != j; 
r = i > j; 
r = i >= j; 
r = i < j; 
r = i <= j; 

Es werden schrittweise die Variablen i und j auf Gleichheit, Ungleichheit, Größer, Größer-Gleich, Kleiner und Kleiner-Gleich überprüft. Das Ergebnis wird in einer Variablen r vom Typ boolean gespeichert, nachdem dies der Datentyp zum Speichern von Wahrheitswerten in Java ist.

Wie die arithmetischen Operatoren auch verändern Vergleichsoperatoren die Operanden nie selber. Um das Ergebnis eines Vergleichs zu speichern, muss also ebenfalls wieder mit dem Zuweisungsoperator = das Ergebnis, nämlich der Wahrheitswert true oder false, in einer Variablen gespeichert werden.

Beachten Sie, dass = der Zuweisungsoperator ist, der Vergleichsoperator == jedoch aus zwei Gleichheitszeichen besteht. Vor allem Anfängern passiert es immer wieder, das zweite Gleichheitszeichen zu vergessen und anstatt einem Vergleich versehentlich eine Zuweisung zu programmieren.

Kommen Ihnen obigen Code-Zeilen ein wenig merkwürdig vor, weil das Vergleichen zweier Werte an sich nicht ganz sinnvoll zu sein scheint, so werden Sie im nächsten Kapitel Kontrollstrukturen kennenlernen, die fast ständig mit Vergleichsoperatoren arbeiten.


7.4 Logische Operatoren

Rechnen mit Wahrheitswerten

So wie arithmetische Operatoren das Rechnen mit Zahlen ermöglichen, können Wahrheitswerte mit logischen Operatoren verrechnet werden. Java bietet drei binäre und einen unären logischen Operator an, die wie folgt definiert sind.

Das logische UND && verknüpft zwei Wahrheitswerte in der Art, dass das Ergebnis der Verknüpfung dann true ist, wenn genau beide Operanden true sind. In allen anderen Fällen ist das Ergebnis der Verknüpfung false.

Das logische ODER || verknüpft zwei Wahrheitswerte in der Art, dass das Ergebnis der Verknüpfung dann true ist, wenn einer der beiden Operanden oder auch beide Operanden true sind. Das Ergebnis ist dann false, wenn also genau beide Operanden false sind.

Java bietet im Gegensatz zu C und C++ ein logisches EXKLUSIVES-ODER an. Das ^ verknüpft zwei Wahrheitswerte in der Art, dass das Ergebnis der Verknüpfung dann true ergibt, wenn genau einer der beiden Operanden true und der andere Operand false ist. Das Ergebnis ist dann false, wenn beide Operanden true oder beide Operanden false sind.

Das logische NICHT ! gibt als Ergebnis true zurück, wenn der Operand false ist, und gibt als Ergebnis false zurück, wenn der Operand true ist. Das logische NICHT ist der unäre Operator und erwartet nur einen Operanden, der hinter ! angegeben werden muss. Daraufhin wird einfach der Wahrheitswert des Operanden umgedreht und zurückgegeben.

boolean i = true, j = false, r; 

r = i && j; 
r = i || j; 
r = i ^ j; 
r = !i; 

Nachdem logische Operatoren Wahrheitswerte verknüpfen, sind im obigen Beispiel die Variablen i und j vom Typ boolean. Das Ergebnis einer logischen Verknüpfung ist ebenfalls wieder ein Wahrheitswert, so dass auch die Variable r, die die Ergebnisse speichert, den Datentyp boolean besitzt.

Beachten Sie, dass auch logische Operatoren niemals den Wert eines Operanden ändern. Logische Operatoren geben als Ergebnis einen Wahrheitswert zurück, der erst wieder in einer Variablen gespeichert werden muss, um weiterverwendet werden zu können.


7.5 Zuweisungsoperatoren

Abkürzungen für faule Programmierer

Den Zuweisungsoperator = haben Sie bereits in unzähligen Beispielen verwendet gehabt. Über ihn ist es überhaupt erst möglich, Werte in Variablen zu speichern. Es handelt sich hierbei auch wieder um einen binären Operator, nachdem sowohl links als auch rechts des = eine Variable oder ein Wert angegeben werden muss. Im Gegensatz zu allen anderen binären Operatoren ist es beim Zuweisungsoperator Pflicht, auf der linken Seite eine Variable anzugeben. Während Sie beispielsweise eine Addition anstatt mit zwei Variablen auch direkt unter Angabe zweier Zahlen durchführen können, muss links vom Zuweisungsoperator immer eine Variable stehen.

Neben diesem einfachen Zuweisungsoperator = stellt Java kombinierte Zuweisungsoperatoren zur Verfügung. Es handelt sich hierbei lediglich um eine abgekürzte Schreibweise, die mit kombinierten Zuweisungsoperatoren möglich wird.

Betrachten Sie dazu folgendes Beispiel.

int i = 10, j = 5; 

i = i + j; 

Im Code werden zwei Variablen vom Typ int angelegt. In der Variablen i wird der Wert 10, in der Variablen j der Wert 5 gespeichert. Dann werden die beiden Variablen addiert und das Ergebnis, nämlich 15, wird in der Variablen i abgelegt. Die Variable i wird also nicht nur zum Berechnen der Summe verwendet, sondern dient gleichzeitig als Speicherort für das Ergebnis. Genaugenommen wird also mit obiger Rechnung die Variable i einfach um den Wert 5 erhöht: Zuerst stand 10 in i, danach steht 15 in der Variablen.

Mit einem kombinierten Zuweisungsoperator sieht der Code wie folgt aus.

int i = 10, j = 5; 

i += j; 

Es handelt sich hierbei lediglich um eine abgekürzte Schreibweise. Genauso wie im vorherigen Code-Beispiel wird auch hier wieder die Variable i um den Wert in der Variablen j - nämlich 5 - erhöht.

So wie sich Addition und Zuweisung kombinieren lassen, können auch Subtraktion, Multiplikation, Division und Modulo-Operation abgekürzt werden: -=, *=, /= und %=.


7.6 Inkrement und Dekrement

Um 1 erhöhen und verringern

Zwei Operatoren, die sich schlecht anderen Kategorien zuordnen lassen, sind der Inkrement- und Dekrement-Operator. Es handelt sich hierbei um unäre Operatoren. Der Operand kann entweder vor oder hinter dem Operator angegeben sein. Die Position des Operanden kann entscheidend sein. Betrachten Sie folgendes Beispiel.

int i, j = 10; 

i = ++j; 
i = j++; 
i = --j; 
i = j--; 

Das ++ ist der Inkrement-Operator, das -- der Dekrement-Operator. Der Inkrement-Operator erhöht eine Variable um den Wert 1, der Dekrement-Operator verringert den Wert einer Variablen um 1. Es handelt sich hierbei also um Operatoren, die nun tatsächlich den Wert des Operanden selber verändern.

Wenn Sie sich obiges Code-Beispiel ansehen, sehen Sie eine nicht initialisierte Variable i und eine Variable j, die mit dem Wert 10 initialisiert ist. In der nächsten Zeile wird mit dem Inkrement-Operator die Variable j um 1 erhöht. Statt 10 enthält j also dann 11. Als Rückgabewert wird in der Variablen i der neue Wert in j gespeichert - also 11.

In der darauffolgenden Zeile wird j wieder um 1 erhöht. Diesmal steht der Inkrement-Operator jedoch hinter dem Operanden. j wird zwar auf den neuen Wert 12 gesetzt, doch als Rückgabewert wird der Variablen i der ursprüngliche Wert - also 11 - zugewiesen.

Die Regel lautet: Steht der Inkrement-Operator vor der Variablen, wird die Variable erhöht und der neue um 1 erhöhte Wert als Ergebnis zurückgegeben. Steht der Inkrement-Operator hinter der Variablen, wird die Variable erhöht und der ursprüngliche noch nicht um 1 erhöhte Wert als Ergebnis zurückgegeben.

Für den Dekrement-Operator trifft die Regel natürlich ebenfalls zu.

Inkrement- und Dekrement-Operatoren werden vor allem in Schleifen häufig verwendet. Schleifen lernen Sie im nächsten Kapitel kennen.


7.7 Präzedenztabelle und Prioritäten

Wer Vorfahrt hat

In jeder Programmiersprache wird die Ausführungsreihenfolge von Operatoren in einer Präzedenztabelle geregelt. Betrachten Sie folgendes Beispiel.

int r; 

r = 10 + 5 * 2; 

Was für ein Ergebnis wird in der Variablen r gespeichert - 30 oder 20? Wird zuerst addiert oder multipliziert? Wird also zuerst der Operator + oder zuerst der Operator * ausgeführt?

So wie in der Mathematik durch die Regel Punkt-vor-Strich festgelegt ist, dass zuerst multipliziert und dann addiert wird, sind in Präzedenztabellen für eine Programmiersprache Prioritäten für Operatoren definiert. In der Präzedenztabelle für Java besitzt der Operator * natürlich auch eine höhere Priorität als der Operator +, so dass selbstverständlich die Punkt-vor-Strich-Regel auch in Java gilt.

Wenn Sie jedoch folgendes Beispiel betrachten, wird es schon recht schwer vorherzusagen, welche Operatoren zuerst ausgeführt werden.

boolean r; 

r = true != false || true; 

Wird in der Variablen r als Ergebnis true oder false gespeichert? In diesem Fall hilft nur noch der Blick in die Präzedenztabelle von Java. Dort werden alle Operatoren ihrer Priorität nach aufgelistet. Ein Blick in die Präzedenztabelle zeigt, dass der Operator != eine höhere Priorität besitzt als der Operator ||. Demnach wird im obigen Beispiel in der Variablen r das Ergebnis true gespeichert.

Wenn Sie sich nicht sicher sind, welcher Operator eigentlich zuerst ausgeführt wird oder nicht, setzen Sie einfach Klammern. Mit Klammern können Sie jederzeit in eine vorgegebene Ausführungsreihenfolge eingreifen. So wird beispielsweise im folgenden Beispiel zuerst die Addition und dann die Multiplikation ausgeführt.

int r; 

r = (10 + 5) * 2; 

Wie in der Mathematik werden Klammern auch in Java von innen nach außen aufgelöst.

Setzen Sie Klammern, um die Ausführungsreihenfolge von Operatoren zu ändern oder zu bekräftigen. Kein Programmierer sucht nach seiner Präzedenztabelle, um die Ausführungsreihenfolge von Operatoren zu überprüfen. Setzen Sie einfach Klammern, wenn Sie nicht sicher sind, und fertig.


7.8 Verketten von Strings

Zeichenketten aneinanderhängen

Dass die Klasse java.lang.String eine ganz besondere Klasse in Java ist, haben Sie bereits öfter gesehen. Diese Klasse können Sie verwenden, ohne sie mit import erst bekanntmachen zu müssen. Sie können neue Objekte vom Typ java.lang.String erstellen, ohne das Schlüsselwort new explizit angeben zu müssen. Auch was die Operatoren betrifft wartet java.lang.String mit einer Besonderheit auf: Das als arithmetischer Operator bekannte Plus-Zeichen kann auch auf Referenzvariablen vom Typ java.lang.String angewandt werden.

import java.applet.*; 
import java.awt.*; 

public class MyApplet extends Applet 
{ 
  String Hallo = "Hallo"; 
  String Welt = "Welt"; 

  public void paint(Graphics g) 
  { 
    g.drawString(Hallo + ", " + Welt + "!", 0, 10); 
  } 
} 

Das Plus-Zeichen angewandt auf Referenzvariablen vom Typ java.lang.String führt keine Addition durch, sondern verkettet die verschiedenen Objekte. Bevor also im obigen Beispiel ein String an die Methode drawString() als erster Parameter weitergegeben wird, wird mit + eine Verkettung verschiedener Strings durchgeführt. Die Strings können hierbei wie Sie sehen als Referenzvariablen vorliegen oder auch direkt in Anführungszeichen angegeben sein.

Dass der Operator + auch auf Strings angewandt werden kann, liegt wieder an der Bevorzugung des Datentyps java.lang.String in Java. Es wird so häufig mit Strings gearbeitet, dass es nur erfreulich ist, wenn es eine einfache Möglichkeit gibt, Strings zu verketten.

Das Plus-Zeichen ist der einzige Operator, der auf Variablen von nicht-primitiven Datentypen angewandt werden kann. Es handelt sich dann um einen binären Operator, der auf Referenzvariablen vom Typ java.lang.String angewandt werden muss. Andere Objekte lassen sich nicht mit + irgendwie verknüpfen - der Compiler generiert dann eine Fehlermeldung.


7.9 Aufgaben

Übung macht den Meister

Sie können die Lösungen zu allen Aufgaben in diesem Buch als ZIP-Datei erwerben.

  1. Entwickeln Sie eine Java-Application, die drei Eigenschaften vom Typ int besitzt. Setzen Sie die Eigenschaften auf die Werte 10, 20 und 30. Addieren Sie die Eigenschaften miteinander, die die Werte 10 und 20 gespeichert haben, und multiplizieren Sie dann das Ergebnis mit der Eigenschaft, in der der Wert 30 gespeichert ist. Geben Sie daraufhin das Ergebnis der Berechnung auf die Standardausgabe aus. Geben Sie außerdem die Rechnung auf die Standardausgabe aus, mit der das Ergebnis zustande kam, damit der Anwender die Rechnung und das Ergebnis nachvollziehen kann.

  2. Entwickeln Sie eine Java-Application, die die Quersumme einer vierstelligen Ganzzahl berechnet und auf die Standardausgabe ausgibt. So soll zum Beispiel für die Zahl 1234 die Quersumme 10 errechnet werden.

  3. Entwickeln Sie eine Java-Application, die die Ziffern einer vierstelligen Ganzzahl umdreht und auf die Standardausgabe ausgibt. So wird zum Beispiel aus der Zahl 1234 die Zahl 4321.

  4. Entwickeln Sie eine Java-Application, in der Sie eine Variable auf drei verschiedenen Wegen - sprich mit drei unterschiedlichen Operatoren - um den Wert 1 erhöhen. Geben Sie nach jeder Erhöhung um 1 den Wert der Variablen zur Kontrolle auf die Standardausgabe aus.

  5. Entwickeln Sie eine Java-Application und definieren Sie drei Variablen vom Typ boolean namens Licht, Strom und Schalter. Erstellen Sie eine derartige Verknüpfung, dass die Variable Licht nur dann auf true gesetzt ist, wenn die Variable Strom und die Variable Schalter auf true gesetzt ist. Geben Sie den Wert der Variablen Licht auf die Standardausgabe aus.

  6. Entwickeln Sie eine Java-Application und definieren Sie drei Variablen vom Typ boolean namens Fahren, Zündschlüssel und Handbremse. Erstellen Sie eine derartige Verknüpfung, dass die Variable Fahren nur dann auf true gesetzt ist, wenn die Variable Zündschlüssel auf true und die Variable Handbremse auf false gesetzt ist. Geben Sie den Wert der Variablen Fahren auf die Standardausgabe aus.

  7. Entwickeln Sie eine Java-Application und definieren Sie zwei Variablen vom Typ boolean namens Raketenstart und Freigabe und eine Variable vom Typ int namens Countdown. Erstellen Sie eine derartige Verknüpfung, dass die Variable Raketenstart nur dann auf true gesetzt ist, wenn die Variable Freigabe auf true und die Variable Countdown auf 0 gesetzt ist. Geben Sie den Wert der Variablen Raketenstart auf die Standardausgabe aus.

  8. Entwickeln Sie eine Java-Application und definieren Sie vier Variablen vom Typ boolean namens Satt, Vorspeise, Steak und Nachspeise. Definieren Sie außerdem zwei Variablen vom Typ int namens Getränke und Kartoffeln. Erstellen Sie eine derartige Verknüpfung, dass die Variable Satt nur dann auf true gesetzt ist, wenn die Variable Vorspeise auf true, die Variable Getränke größer oder gleich 3, die Variable Kartoffeln größer oder gleich 2 und die Variable Steak auf true gesetzt ist. Statt der Variablen Steak kann auch die Variable Nachspeise auf true gesetzt sein, damit die Variable Satt true ergibt. Geben Sie den Wert der Variablen Satt auf die Standardausgabe aus.