Operatoren werden in drei Kategorien Unterteilt. Je nachdem ob sie sich nur auf einen Operanden auswirken (unary operator), auf deren zwei (binary operator) oder gar auf drei (ternary operator). Zu jeder dieser drei Kategorien ein Beispiel:
Operator |
Beschreibung |
Kategorie |
---|---|---|
i++ |
Erhöhen der Variablen i um 1 |
unary operator |
i = 1 |
Belegen der Variablen i mit 1 |
binary operator |
a ? b : c |
wenn a true return b sonst return c |
ternary operator |
Soweit die Kategorien. Die folgenden Abschnitte werden sich mit allen Operatoren auseinandersetzen, auch mit solchen die nicht unbedingt als Opeartor angesehen werden.
Am häufigsten werden wohl Opeartoren für Berechnungen eingesetzt. Letztere sind arithmetischer Natur und werden deshalb zuerst betrachtet.
Operator |
Benutzung |
Beschreibung |
---|---|---|
+ |
a + b |
Addiert Oparand a und Operand b |
- |
a - b |
Subtrahiert Operand a von Operand b |
* |
a * b |
Multipliziert Operand a und Operand b |
/ |
a / b |
Dividiert Operand a durch Operand b |
% |
a % b |
Ermittelt den Rest der Division a / b |
Die Strichoperatoren besitzen noch eine weitere unäre Eigenschaft. Sie werden auch als Vorzeichen eingesetzt und haben dann fogende Bedeutung:
Operator |
Benutzung |
Beschreibung |
---|---|---|
+ |
+a |
positives Vorzeichen |
- |
-a |
Negation des Operanden a |
Strichoperatoren in ihrer in- und dekrementierenden Kurzform (++ / --) sind ebenfalls unär, haben aber noch die Möglichkeit ihre Funktionalität prefix oder postfix auszuüben.
Operator |
Benutzung |
Beschreibung |
---|---|---|
++ |
++a |
a+1 vor Ausführung der Aktion |
++ |
a++ |
a+1 nach Ausführung der Aktion |
-- |
--a |
a-1 vor Ausführung der Aktion |
-- |
a-- |
a-1 nach Ausführung der Aktion |
Diese Operatoren werden korrekterweise relationale Operatoren genannt, aber die Bezeichnung Vergleichsoperator hat sich in unserem Sprachraum durchgesetzt. Die folgende Tabelle zeigt wieder den Opeartor und seine Benutzung, in der dritten Spalte wird nun aber als Berschreibung angegeben wann das Ergebnis den logischen Wert true (wahr ) ergibt.
Operator |
Benutzung |
Ergibt true wenn |
---|---|---|
> |
a > b |
a ist größer als b |
>= |
a >= b |
a ist größer oder gleich b |
< |
a < b |
a ist kleiner als b |
<= |
a <= b |
a ist kleiner oder gleich b |
== |
a == b |
a ist gleich b |
!= |
a != b |
a ist ungleich b |
Conditional operators sind wohl meist gehasste Gebiet der Programmierung. Nicht weil sie besonders schwierig sind, sonder weil kaum Informationen über den jeweiligen Compiler zur Verfügung stehen, wie denn nun diese Operatoren arbeiten. Wird immer der gesamte Ausdruck ausgewertet oder endet die Auswertung nach dem Test relevanter Werte? Ist die Konjunktion mit einer Punktoperation auf gleicher Priorität oder müssen die Ausdrücke komplett geklammert sein? Die folgende Tabelle wird um ein Beispiel ergänzt, das auf die feinen aber oft nervigen Unterschiede aufmerksam macht.
Operator |
Benutzung |
Ergibt true wenn |
---|---|---|
&& |
a && b |
a und b gleich true sind (Auswertung des Operators b ist abhängig von a) |
|| |
a || b |
a oder b gleich true ist (Auswertung des Operators b ist abhängig von a) |
! |
!a |
a gleich false ist |
& |
a & b |
a und b gleich true sind (Es werden immer beide Operatoren ausgewertet) |
| |
a | b |
a oder b gleich true ist (Es werden immer beide Operatoren ausgewertet) |
^ |
a ^ b |
a und b unterschiedlich sind (Es werden immer beide Operatoren ausgewertet) |
Schleife mit Überprüfung der Abbruchbedingung, die jedoch nie erreicht wird:
do { ... } while((idx < length) || (arr[++idx] != 0)) |
Offensichtlich soll irgendein Array durchsucht werden, das kürzer als eine vorgegebene Länge (length) sein kann. Die Schleife soll verlassen werden, wenn der laufende Index (idx) größer oder gleich der vorgegebenen Länge ist, oder an der unmittelbar folgenden Position (idx + 1) im Array der Wert 0 gefunden wird. Wenn der Index auch nur eimal kleiner als die vorgegebene Länge ist, wird diese Schleife nie verlassen. Die Abbruchbedingung für das Verlassen der Schleife exit besteht aus zwei Opearanden, wobei der zweite auch noch einen prefix short cut opearator (++idx) enthält. Zur besseren Übersicht wird der eigentliche Inhalt farblich getrennt dargestellt. Operand-1 grün und Operand-2 blau.
if (idx >= length) exit; else { idx = idx + 1; if (arr[idx] == 0) exit; } |
Der zweite Opearand wird nur ausgewertet, wenn die Bedingung des ersten der boolschen Wert false ergibt. Weil die Incrementierung des Index aber als short cut opratator im zweiten boolschen Operanden steckt, wird der Index nicht erhöht, weil der zweite Opearand überhaupt nicht zur Ausweruntg gelangt.
Diese Operatoren haben zwar, bis auf
eine Ausnahme, die gleiche Notation wie die Konditionaloperatoren,
sind aber nicht identisch. Ihre Auswirkung ist von der aktuellen
Algebra abhängig, womit prinzipiell der Typus der Operatoren
gemeint ist. Dieser verwirrende Zusammenhang soll zunächst
erläutert werden, bevor die Tabelle mit den Operatoren
dergestellt wird.
Die Boolsche Algebra ist in Java ein
abgeschlossenes System. In anderen Programmiersprachen ist dieser
Unterschied nicht vorhanden. Wenn ein Boolscher Ausdruck mit 0 oder 1
statt true oder false assoziiert wird, kann das System entweder den
logischen Wert true mit nicht Null oder den logischen Wert false mit
nicht 1 gleichsetzen. Damit muss immer ein Schwellenwert
berücksichtigt werden, der keinesfalls eindeutig ist. Im
Gegensatz dazu steht die Abgeschlossenheit Boolscher Operationen bei
Java. Hier ist gewährleistet, dass nicht true immer false
bedeutet und nicht false nur true nach sich ziehen kann.
Nun
bestehen Daten bekanntlich aus sinnvollen Kombinationen einzelner
Bits, die ihrerseits nur als 0 oder 1 repräsentiert werden. Die
Manipulation einzelner Bits ist die Aufgabe der logischen Operatoren.
Die Bits können zwar auch Synonyme der Boolschen Werte true oder
false angesehen werden, jedoch sind Bits mit einer Positionierung
versehen, die dem Verbund (z.B. Byte) in dem sie residieren Werte
oder andere Eigenschaften zuordnen. Die Binäre Verknüpfung
der Werte 10 und 7 ergibt:
1010 = 10 &0111 = 7 ---- 0010 = 2 |
Logische Operatoren verknüpfen also immer alle Bits, derer sie habhaft werden können. Sie nehmen praktisch alle Boolschen Werte aus den Bytes und verküpfen sie im Verbund. Deshalb haben sie die gleiche Notation wie die Konditionaloperatoren.
Operator |
Benutzung |
Auswirkung |
a=1010, b=0111 |
---|---|---|---|
& |
a & b |
Bitweise UND-Verknüpfung |
0010 |
| |
a | b |
Bitweise ODER-Verknüpfung |
1111 |
^ |
a ^ b |
Bitweise XOR-Verknüpfung |
1101 |
~ |
~a |
Bitweise Negation (Einerkomplement) |
0101 |
Verbunde aus Bits, seien sie vorhanden
als Byte oder Integer, könne auch verschoben werden. Diese
Operation entspricht, je nach Richtung, einer Multilikation oder
einer Division. In Java sind folgende Shift Operatoren vorhanden:
Operator |
Benutzung |
Beschreibung |
---|---|---|
>> |
a >> b |
Verschiebung von a um b Bits nach rechts (a / 2b) |
<< |
a << b |
Verschiebung von a um b Bits nach links ( a . 2b) |
>>> |
a >>> b |
Verschiebung von a um b Bits nach rechts (unsigned) |
Java bietet nicht nur den üblichen binären Zuweisungsopeartor "=" an, sondern gestattet siene Verwendung auch als short cut operator mit folgenden Zusätzen:
Operator |
Benutzung |
Gleichbedeutend mit |
---|---|---|
+= |
a += b |
a = a + b |
-= |
a -= b |
a = a - b |
*= |
a *= b |
a = a * b |
/= |
a /= b |
a = a / b |
%= |
a %= b |
a = a % b |
&= |
a &= b |
a = a & b |
|= |
a |= b |
a = a | b |
^= |
a ^= b |
a = a ^ b |
<<= |
a <<= b |
a = a << b |
>>= |
a >>= b |
a = a >> b |
>>>= |
a >>>= b |
a = a >>> b |
Es existieren noch einige Operatoren, die als solche nicht unmittelbar erkenntlich sind aber gleichwohl existentiell für die Sprache Java.
Oft werden unterschiedliche Genauigkeiten bei Berechnungen
verlangt, weshalb einige Werte vor der Operation in den
entsprechenden Datentyp gewandelt werden müssen. Der Typecasting
Operator übernimmt diese Aufgabe.
Anwendung: (type)var
Beispiel: (double)val
Die Variable "val"
wird in den Typ double überführt. Die Variable "val"
muß in diesem Beispiel dem Typ eines numerischen primitive
entsprechen.
Oft muss festgestellt werden, welcher Klasse die Instanz eines
Objektes entspricht. Dafür ist der instanceof Operator bestens
geeignet.
Anwendung: a instanceof b
Dabei verkörpert
a den Namen eines Objektes und b die Bezeichnung einer Klasse. Wenn
nun das Objekt (a) einer Instanz der Klasse (b) entspricht, wird true
zurückgegeben. Dieser Operator arbeitet über die Grenzen
der abgeleiteten Klassen hinaus. Ein Beispiel:
Ein Objekt a ist
die Instanz einer Schaltfläche (Button), die Klasse b ist
Synonym mit Component. Die Anweisung a instanceof b liefert true,
weil jede Schaltfläche eine Instanz der Klasse Component ist.
Wenn b allerdings die Klasse Container verkörpert, würde
die gleiche Anweisung false liefern, weil zwar jeder Container eine
Instanz von Component ist, jedoch kein Button der Instanz eines
Containers entspricht. Klingt kompliziert? Ist es auch.
Auch die Kreation neuer Objekte besitzt einen eigenen Operator. Dieser Operator benutzt direkt die Creator-Methode von Ojekten zu deren Instanzierung. Er ist der einzige Operator, der diese Methode benutzen kann.
Der Zugriff auf objekinterne Elemente erfolgt über den dot (".") Operator. Wenn beispielsweise auf die member variable "day" eines Objektes "date" der Klasse "Date" zugegriffen werden soll wird der dot Operator in der Form
int Tag = date.day; |
benutzt.
Dieser Operator (runde Klammer, runde Klammer zu) hat eigentlich zwei Aufgaben. Zunächst ist er unabkömmlich für die Deklaration von Methoden. Außerdem dient er als Container für die Argumentliste der deklarierten Methode. Auch wenn keine Argumente existieren, muß der () Operator angewendet werden, um dem Compiler die Assoziation von identifier und Methode mitzuteilen.
Die Deklaration von Arrays erfolgt über diesen Operator. Auch der Zugriff auf einzelne Elemente von Arrays efolgt hierüber. Ein Beispiel:
double[] double_array = new double[15]; |
Ein Array mit 15 Elementen des numerischen primitive Typs "double" wird instanziert. Der identifier "double_array" ist zwar nur eine Referenz auf die Instanz des gesamten Arrays, über die Benutzung der [] Opearators kann jedoch auf einzelne Elemente zugegriffen werden. So liefert die Anweisung double_array[6] den Inhalt des sechsten Elements.