next up previous contents index
Nächste Seite: Anweisungen Aufwärts: Programmieren in Java Vorherige Seite: Arrays   Inhalt   Index

Unterabschnitte

Grundsymbole, Operatoren und Ausdrücke

In diesem Kapitel geht es um den grundlegenden Aufbau von Java-Programmen.




Unicode-Buchstaben

Java benutzt nicht 8-bit Zeichensätze wie ASCII oder EBCDIC sondern den 16-Bit Zeichensatz Unicode.



Die ersten 256 Zeichen des Unicode sind identisch mit der ASCII-Variante Latin-1.



Die meisten anderen Zeichen sind mit unseren Editoren nicht darstellbar, daher gibt es eine Escape-Schreibweise:


    \uddd     (d ist Hexadezimalziffer)


\psfig {figure=bilder/unicode.ps}

Kommentare

Drei Kommentar-Stile

Siehe Seite [*].




Bezeichner

Buchstabe (einschließlich _ und $), gefolgt von Buchstaben und Ziffern.



Wegen Unicode umfassen Buchstaben und Ziffern jedoch alle erdenklichen Zeichen fast aller geschriebenen Sprachen.

Reservierte Wörter



abstract double int static
boolean else interface super
break extends long switch
byte final native synchronized
case finally new this
catch float null throw
char for package throws
class goto * private transient *
const * if protected try
continue implements public void
default import return volatile
do instanceof short while




Mit * markierte Schlüsselwörter sind reserviert aber (noch) nicht verwendet.

Grundtypen

Ganze Zahlen:



byte 8-bit 2er Komplement Byte
short 16-bit 2er Komplement Kurz-Integer
int 32-bit 2er Komplement Integer
long 64-bit 2er Komplement Lang-Integer




Fließpunktzahlen



float 32-bit IEEE 754 Einfachpräzision
double 64-bit IEEE 754 Doppelpräzision




Andere Typen



char 16-bit Unicode-Zeichen Buchstabe
boolean wahr oder falsch Boolescher Wert





Literale



Ganze Zahlen:



Oktaldarstellung 052
Dezimaldarstellung 42
Hexadezimaldarstellung 0x2A





Fließpunktzahlen

Vier Schreibweisen:


   Digits . [Digits] [Expo] [FloatSuffix]
        z.B. 3.1E4
   . Digits [Expo] [FloatSuffix]
        z.B. .1F
   Digits Expo [FloatSuffix]
        z.B 17e12
   Digits [Expo] FloatSuffix
        z.B. 0F

Ohne ``FloatSuffix'' ist der Typ double.




Buchstaben

Buchstaben-Literale werden in einfache Anführungszeichen eingeschlossen: 'p'.



Die folgenden Escape-Sequenzen sind definiert:

$\backslash$n newline $\backslash$t Tabulator
$\backslash$b backspace $\backslash$r return
$\backslash$f form feed $\backslash \backslash$ der Backslash selbst
$\backslash$' single quote $\backslash$" double quote
$\backslash$ddd Oktalwertdarstellung    





Boolesche Werte

entweder true oder false.





Deklaration von Variablen

Eine Deklaration legt Zugriffsbeschränkungen, Typ und andere Eigenschaften eines Bezeichners fest.



Form:


    Modifier Type Identifier_List



Modifier sind



public
private static synchronized
protected



Diese Reihenfolge wird empfohlen, im Prinzip ist sie aber beliebig.

Es gibt 7 Arten von Variablen:



Initialisierung

Wenn der Initialisierungsausdruck bei der Deklaration fehlt, bekommen Attribute Default-Werte:



Typ Default
boolean false
char \u0000
byte 0
short 0
int 0
long 0
float 0.0
double 0.0
Klasse, Interface, Array null




Lokale Variablen in Methoden, Konstruktoren und Initialisierungsblöcken bekommen keine Default-Werte!

Verwendung führt zu Fehler:

Beispiel:




  class UnInit
  { static public void main(String av[])
    { double d;
      if (true)
        d=9.9;
      else ;
      System.out.println(d); // FEHLER
    }
  }

liefert die Compiler-Fehlermeldung


  Variable d may not have been initialized





Namensanalyse

Durch seine Deklaration lebt jeder Bezeichner in einem bestimmten Namensraum. Alle Bezeichner in einem Namensraum müssen verschieden sein.




Wird ein Bezeichner angewendet, muß festgestellt werden, in welchem Namensraum er lebt um dann auf seine deklarierten Eigenschaften zugreifen zu können.

Der gleiche Bezeichner darf in verschiedenen Namensräumen leben:


class Reuse
{ Reuse Reuse(Reuse Reuse)
    { Reuse:
      for (;;)
      { if (Reuse.Reuse(Reuse) == Reuse)
        break Reuse;
      }
      return Reuse;
    }
}




Namensräume in Java






Die Namensräume sind geschachtelt, dh. Deklarationen in inneren Strukturen können die Deklarationen in äußeren Strukturen verdecken.



Beispiel:

der Name eines Konstruktorparameters überdeckt den Namen einer Instanzvariable.


   class MyClass
   { T myattr;
     MyClass (T myattr)
     { this.myattr = myattr;
     }
   }



Ausnahme:

Die Schachtelung von Blöcken und for-Schleifen kann nicht dazu benutzt werden, Bezeichner aus äußeren Blöcken, for-Schleifen und Methoden-Parameter zu überdecken.


class Nesti
{ static public void main(String a[])
  { double d = 9.9;
    for (int i = 0; i < 10; i++)
      { int d;  // FEHLER
        boolean a; // FEHLER
        char i; // FEHLER
        ...
      }
  }
}

liefert


  'd' is already defined in this method.
  'a' is already defined in this method.
  'i' is already defined in this method.



Konventionen für die Verwendung von Bezeichnern

Ziel:

Diese Bezeichnerkonventionen sind Empfehlungen, man muß sich nicht sklavisch daran halten.

So sind z.B. sin und cos aus der Bibliothek java.lang.Math Bezeichner, die gegen die Java-Konventionen verstoßen, sie sind aber üblich.




Klassen und Interfaces

Beispiele:


   ClassLoader
   BufferedInputStream
   HalloWelt


Methoden

Beispiele:


   sayHello()
   printDataFile()



Zusatzregeln:






Konstanten

Beispiele:


   MAX_VALUE
   MIN_TEMP


Variablen und Parameter

Beispiele:


   buf
   cp
   len
   out






Operatorpräzedenz und -assoziativität

Präzedenz beschreibt die ``Bindungskraft'' von Operatoren.

So ist


    3 * 5 - 3

12 und nicht 6, und


   (i >= min && i <= max)

prüft ob i zwischen min und max liegt.



Sind zwei Operatoren gleicher Präzedenz in einem Ausdruck benachbart, so bestimmt die Assoziativität, welcher von beiden zuerst ausgewertet wird.




   a + b + c

bedeutet (da die Addition linksassoziativ ist)


   (a + b) + c



Die Operatorpräzedenzen absteigend geordnet:




Operator-Art Operatoren
Postfix-Operator [] . (params ) expr ++ expr -
Unärer Operator ++expr -expr +expr -expr ! ~
Erzeugung oder Typ-Cast new (type )expr
Multiplikation * / %
Addition + -
Shift << >> >>>
Relational < > <= >= instanceof
Gleichheit == !=
bitweises AND &
bitweises XOR ^
bitweises OR |
logisches AND &&
logisches OR ||
Bedingung ? :
Zuweisung = += -= *= /= %= >>= <<=
  >>>= &= ^= = |=




Alle Wertzuweisungen sind rechtsassoziativ, die anderen binären Operatoren sind linksassoziativ.



Mit Klammern kann die Operatorbindung beeinflußt werden:


   while ((v = stream.next()) != null)
   { ...
   }






Auswertungsreihenfolge

Java garantiert, daß die Operanden von Operatoren von links nach rechts ausgewertet werden.



Im Ausdruck


   x + y + z

wird also niemals y vor x oder z vor x oder y ausgewertet.





Auswertungsreihenfolge ist natürlich nur beobachtbar für Operanden mit Seiteneffekten,

z.B.

Außer bei den Operatoren &&, || und ?: werden stets alle Operanden ausgewertet, bevor eine Operation ausgeführt wird.





Typanpassung

Typanpassung tritt auf bei Wertzuweisungen, Ausdrücken und Parameterübergaben.

Wir unterscheiden:







Implizite Typanpassung

Hier unterscheiden wir die Typanpassung für Grundtypen und die für Referenztypen.



Bei Grundtypen wird implizit zwischen zwei Typen konvertiert, wenn der Bereich des Zieltyps größer oder gleich ist.



Zum Beispiel:

Zwischen char und int
Zwischen long und float
Zwischen float und double




Bei Referenztypen wird implizit konvertiert zwischen einem Typ T und seinen Obertypen.




Explizite Typanpassung

Explizite Casts erlauben Typanpassungen, bei denen der Zieltyp den kleineren Wertebereich umfaßt:


   double d = 7.88;
   long l = (long) d;



Explizite Casts also z.B.

Zwischen double und float
Zwischen Fließpunkt und Ganzzahl
Von long nach int, short, byte oder char.



Bei solchen Typanpassungen kann man Genauigkeit verlieren:


   short s = -134;
   byte b = (byte) s;

Die vorderen Bits gehen verloren: b hat den Wert 122.




Für Referenztypen erlauben explizite Casts Typumwandlungen entgegen der Klassenhierarchie, also z.B. vom Obertyp zum Untertyp



Solche Typumwandlungen heißen



Sie erfordern einen Laufzeittest, ob das aktuelle Objekt tatsächlich für den Zieltyp zulässig ist. Wenn nicht: ClassCastException.



Beispiel:




class Ober{}
class Unter extends Ober{}
public class Classcast
{ public static void main(String argv[])
  { Ober objo = new Ober();
    Unter obju = (Unter) objo;
  }
}

liefert Laufzeit-Fehler


    java.lang.ClassCastException: Ober




Mögliche Down-Casts:



Diese Down-Casts erfordern Laufzeittests, ob der tatsächliche Wert für den Zieltyp zulässig ist.





String Konvertierung

Es gibt Typanpassungen von jedem Typ (einschließlich Null) nach String.



Verbotene Typanpassungen:



Operatoren






Arithmetik

+ op1 + op2 Addiert op1 und op2
- op1 - op2 Subtrahiert op2 von op1
* op1 * op2 Multipliziert op1 mit op2
/ op1 / op2 Dividiert op1 durch op2
% op1 % op2 Berechnet den Rest der Division op1 durch op2

Außerdem zwei unäre Operatoren

+ + op1 Unäres Plus (aus Symethrie-Gründen)
- - op1 Unäres Minus, Negation



Java rechnet ganzzahlig in Zweierkomplement-Arithmetik. Nichts kann über- oder unterlaufen.



Für die Gleitpunkt-Arithmetik wird eine Untermenge des IEEE 754-1985-Standards benutzt. Es gibt ausgezeichnete Werte für +$\infty$, -$\infty$ und NaN (not a number) und Rechenregeln dazu.

String-Konkatenation

+ wird zur String-Konkatenation verwendet:


    String boo = "boo";
    String cry = boo + "hoo";
    cry += "!";
    System.out.println(cry);

liefert


   boohoo!

Die implizite Konvertierung nach String gibt es nur im Zusammenhang mit dem Operator +:


    String s;
    s = '@' + s + 3.14;

aber z.B. nicht bei der Parameterübergabe an String-Parameter.



Inkrement/Dekrement

++ op++ Erhöht op um 1, liefert Wert vor Inkrement
++ ++op Erhöht op um 1, liefert Wert nach Inkrement
- op- Erniedrigt op um 1, liefert Wert vor Dekrement
- -op Erniedrigt op um 1, liefert Wert nach Dekrement


Vergleich und logische Operatoren



Vergleichsoperatoren

> op1 > op2 op1 ist größer als op2
>= op1 >= op2 op1 ist größer oder gleich op2
< op1 < op2 op1 ist kleiner als op2
<= op1 <= op2 op1 ist kleiner oder gleich op2
== op1 == op2 op1 und op2 sind gleich
!= op1 != op2 op1 und op2 sind nicht gleich

Diese Operatoren liefern Boolesche Werte.





Logische Operatoren



&& op1 && op2 op1 und op2 sind beide true
|| op1 || op2 op1 oder op2 ist true
! ! op op ist false

Diese Operatoren werten ihre rechten Operanden nicht aus, wenn der linke bereits das Ergebnis bestimmt ( Boolesche Kurzauswertung).




Der bedingte Operator ?:

Erlaubt Ausdrücke, die abhängig von einer Bedingung einen von zwei Werten liefern:


   val = userSetIt ? usersVal : defaultVal;

Der Typ eines der Ausdrücke muß dem Typ des anderen Ausdrucks ohne expliziten Cast zuweisbar sein. Der allgemeinere Typ der beiden bestimmt das Ergebnis. Dies gilt auch für Referenztypen.



Bit-Operationen



>> op1 >> op2 Rechtsshift von op1 um op2 Stellen
>>> op1 >>> op2 dto. aber von links 0 nachziehen
<< op1 << op2 Linksshift von op1 um op2 Stellen
& op1 & op2 bitweises UND
| op1 | op2 bitweises ODER
^ op1 ^ op2 bitweises Exclusiv-Oder
~ ~op2 bitweises Komplement

Bitweise Operationen dürfen nur auf ganzen Zahlen und Booleschen Werten ausgeführt werden.



Zuweisungen



+= op1 += op2 op1 = op1 + op2
-= op1 -= op2 op1 = op1 - op2
*= op1 *= op2 op1 = op1 * op2
/= op1 /= op2 op1 = op1 / op2
%= op1 %= op2 op1 = op1 % op2
&= op1 &= op2 op1 = op1 &= op2
|= op1 |= op2 op1 = op1 | op2
^= op1 ^= op2. op1 = op1 ^ op2
<<= op1 <<= op2 op1 = op1 << op2
>>= op1 >>= op2 op1 = op1 >> op2
>>>= op1 >>>= op2 op1 = op1 >>> op2



next up previous contents index
Nächste Seite: Anweisungen Aufwärts: Programmieren in Java Vorherige Seite: Arrays   Inhalt   Index
Peter Pfahler, 1997