Skip to content

2. Grundlagen der Programmiersprache Java

2.1. Einführung

Wir behandeln Java zunächst als klassische Programmiersprache. Auf Objekte werden wir später eingehen.

In einem Programm gibt es zwei Arten von Elementen

  • Daten
  • Anweisungen, die diese bearbeiten

Man ist im Allgemeinen bestrebt, die Daten von den Anweisungen zu trennen:

Image

2.2. Daten in Java

Java verwendet die folgenden Datentypen:

  • Ganzzahlen
  • Reelle Zahlen
  • Zeichen und Zeichenfolgen
  • Boolesche Werte
  • Objekte

2.2.1. Vordefinierte Datentypen

Typ
Kodierung
Bereich
char
2 Byte
Unicode-Zeichen
int
4 Bytes
[-231, 231-1]
long
8 Bytes
[-263, 263 -1]
byte
1 Byte
[-27 , 27 -1]
short
2 Bytes
[-215, 215-1]
float
4 Bytes
[3.4 10-38, 3.4 10+38] als Absolutwert
double
8 Bytes
[1.7 10-308 , 1.7 10+308] als Absolutwert
boolean
1 Bit
wahr, falsch
String
Objektreferenz
Zeichenkette
Date
Objektreferenz
Datum
Character
Objektreferenz
char
Integer
Objektreferenz
int
Long
Objektreferenz
long
Byte
Objektreferenz
Byte
Float
Objektreferenz
Float
Double
Objektreferenz
double
Boolean
Objektreferenz
bool

2.2.2. Notation von Literalwerten

entier
145, -7, 0xFF (hexadezimal)
Double
134,789, -45E-18 (-45 × 10⁻¹⁸)
Float-Zahl
134.789F, -45E-18F (-45 × 10⁻¹⁸)
caractère
'A', 'b'
Zeichenkette
„heute“
booléen
true, false
date
new Date(13,10,1954) (Tag, Monat, Jahr)

2.2.3. Datenmeldung

2.2.3.1. Rolle der Deklarationen

Ein Programm verarbeitet Daten, die durch einen Namen und einen Typ gekennzeichnet sind. Diese Daten werden im Speicher abgelegt. Bei der Übersetzung des Programms weist der Compiler jedem Datenelement einen Speicherplatz zu, der durch eine Adresse und eine Größe gekennzeichnet ist. Dabei stützt er sich auf die vom Programmierer vorgenommenen Deklarationen.

Außerdem ermöglichen diese dem Compiler, Programmierfehler zu erkennen. So wird die Operation

x = x * 2;

wird beispielsweise als fehlerhaft deklariert, wenn x eine Zeichenkette ist.

2.2.3.2. Deklaration von Konstanten

Die Syntax zur Deklaration einer Konstante lautet wie folgt:

final Typ Name = Wert; //definiert die Konstante „Name“ = „Wert“

Beispiel: final float PI=3.141592F;

Hinweis

Warum Konstanten deklarieren?

  • Das Programm lässt sich leichter lesen, wenn man der Konstante einen aussagekräftigen Namen gibt:

Beispiel: final float taux_tva = 0.186F;

  • Die Änderung des Programms wird einfacher, falls sich die „Konstante“ ändern sollte. Wenn also im vorigen Fall der Mehrwertsteuersatz auf 33 % steigt, muss lediglich die Anweisung geändert werden, die ihren Wert definiert:

final float taux_tva=0.33F;

Hätte man im Programm explizit den Wert 0,186 verwendet, müssten zahlreiche Anweisungen geändert werden.

2.2.3.3. Deklaration von Variablen

Eine Variable wird durch einen Namen identifiziert und bezieht sich auf einen Datentyp. Der Name einer Java-Variablen besteht aus n Zeichen, wobei das erste ein Buchstabe sein muss und die übrigen Buchstaben oder Ziffern sein können. Java unterscheidet zwischen Groß- und Kleinschreibung. Daher sind die Variablen „FIN“ und „fin“ unterschiedlich.

Variablen können bei ihrer Deklaration initialisiert werden. Die Syntax zur Deklaration einer oder mehrerer Variablen lautet:

identificateur_de_type variable1,variable2,...,variablen;

wobei identificateur_de_type ein vordefinierter Typ oder ein vom Programmierer definierter Objekttyp ist.

2.2.4. Konvertierungen zwischen Zahlen und Zeichenketten

Zahl -> Zeichenkette
"" + Zahl
Zeichenkette -> int
Integer.parseInt(Zeichenkette)
Zeichenkette -> long
Long.parseLong(Zeichenkette)
Zeichenkette -> double
Double.valueOf(Zeichenkette).doubleValue()
Zeichenkette -> Float
Float.valueOf(Zeichenkette).floatValue()

Hier ist ein Programm, das die wichtigsten Techniken zur Konvertierung zwischen Zahlen und Zeichenfolgen vorstellt. Die Konvertierung einer Zeichenfolge in eine Zahl kann fehlschlagen, wenn die Zeichenfolge keine gültige Zahl darstellt. In diesem Fall wird ein schwerwiegender Fehler ausgelöst, der in Java als „Exception“ bezeichnet wird. Dieser Fehler kann durch die folgende Klausel try/catch behandelt werden:

try{
    appel de la fonction susceptible de générer l'exception
} catch (Exception e){
    traiter l'exception e
}
instruction suivante

Wenn die Funktion keine Ausnahme auslöst, wird zur nächsten Anweisung übergegangen; andernfalls wird der Hauptteil der Klausel catch aufgerufen und anschließend zur nächsten Anweisung übergegangen. Wir werden später noch auf die Ausnahmebehandlung zurückkommen.


import java.io.*;

public class conv1{

  public static void main(String arg[]){
    String S;
    final int i=10;
    final long l=100000;
    final float f=(float)45.78;
    double d=-14.98;

    // Zahl --> Zeichenkette
    S=""+i;
    affiche(S);
    S=""+l;
    affiche(S);
    S=""+f;
    affiche(S);
    S=""+d;
    affiche(S);

    //Boolescher Wert --> Zeichenfolge
    final boolean b=false;
    S=""+new Boolean(b);
    affiche(S);

    // Zeichenkette --> int
    int i1;
    i1=Integer.parseInt("10");
    affiche(""+i1);
    try{
      i1=Integer.parseInt("10.67");
      affiche(""+i1);
    } catch (Exception e){
      affiche("Erreur "+e);
    }

    // Zeichenkette --> long
    long l1;
    l1=Long.parseLong("100");
    affiche(""+l1);
    try{
      l1=Long.parseLong("10.675");
      affiche(""+l1);
    } catch (Exception e){
      affiche("Erreur "+e);
    }
    
    // Zeichenkette --> double
    double d1;
    d1=Double.valueOf("100.87").doubleValue();
    affiche(""+d1);
    try{
      d1=Double.valueOf("abcd").doubleValue();
      affiche(""+d1);
    } catch (Exception e){
      affiche("Erreur "+e);
    }

    // Zeichenkette --> Float
    float f1;
    f1=Float.valueOf("100.87").floatValue();
    affiche(""+f1);
    try{
      d1=Float.valueOf("abcd").floatValue();
      affiche(""+f1);
    } catch (Exception e){
      affiche("Erreur "+e);
    }

}// Ende main

  public static void affiche(String S){
    System.out.println("S="+S);
  }
}// Ende der Klasse

Die folgenden Ergebnisse wurden erzielt:

S=10
S=100000
S=45.78
S=-14.98
S=false
S=10
S=Erreur java.lang.NumberFormatException: 10.67
S=100
S=Erreur java.lang.NumberFormatException: 10.675
S=100.87
S=Erreur java.lang.NumberFormatException: abcd
S=100.87
S=Erreur java.lang.NumberFormatException: abcd

2.2.5. Datentabellen

Ein Java-Array ist ein Objekt, mit dem Daten desselben Typs unter einem gemeinsamen Bezeichner zusammengefasst werden können. Die Deklaration lautet wie folgt:

Typ Array[] = new Typ[n] oder Typ[] Array = new Typ[n]

Beide Syntaxen sind zulässig. n ist die Anzahl der Daten, die das Array enthalten kann. Die Syntax Array[i] bezeichnet das Datenelement Nr. i, wobei i zum Intervall [0,n-1] gehört. Jeder Verweis auf den Datenpunkt „Tableau[i]“, bei dem „i“ nicht zum Intervall „[0,n-1]“ gehört, löst eine Ausnahme aus.

Ein zweidimensionales Array kann wie folgt deklariert werden:

Typ Array[][] = new Typ[n][p] oder Typ[][] Array = new Typ[n][p]

Die Syntax „Tableau[i]“ bezeichnet den Datensatz Nr. i von Tableau, wobei i zum Intervall [0,n-1] gehört. „Tableau[i]“ ist selbst ein Array: „Tableau[i][j]“ bezeichnet den Datensatz Nr. j aus „Tableau[i]“, wobei j zum Intervall [0,p-1] gehört. Jeder Verweis auf einen Datensatz aus „Tableau“ mit falschen Indizes führt zu einem schwerwiegenden Fehler.

Hier ein Beispiel:


public class test1{

  public static void main(String arg[]){
    float[][] taux=new float[2][2];
    taux[1][0]=0.24F;
    taux[1][1]=0.33F;
    System.out.println(taux[1].length);
    System.out.println(taux[1][1]);
  }
}

und die Ergebnisse der Ausführung:

2
0.33

Ein Array ist ein Objekt mit dem Attribut length: Dies ist die Größe des Arrays.

2.3. Die Grundanweisungen in Java

Man unterscheidet

  • zwischen den vom Computer ausgeführten Grundbefehlen
  • die Anweisungen zur Steuerung des Programmablaufs.

Die elementaren Befehle werden deutlich, wenn man die Struktur eines Mikrocomputers und seiner Peripheriegeräte betrachtet.

Image

  1. Einlesen von Informationen von der Tastatur

  2. Verarbeitung von Informationen

  3. Ausgabe von Informationen auf dem Bildschirm

  4. Einlesen von Informationen aus einer Datei auf der Festplatte

  5. Schreiben von Informationen in eine Datei auf der Festplatte

2.3.1. Ausgabe auf dem Bildschirm

Die Syntax des Befehls zum Schreiben auf den Bildschirm lautet wie folgt:

System.out.println(Ausdruck) oder System.err.println(Ausdruck)

wobei expression ein beliebiger Datentyp ist, der in eine Zeichenkette umgewandelt werden kann, um auf dem Bildschirm angezeigt zu werden. Im vorangegangenen Beispiel haben wir zwei Schreibanweisungen gesehen:

System.out.println(taux[1].length);
System.out.println(taux[1][1]);

System.out schreibt in eine Textdatei, bei der es sich standardmäßig um den Bildschirm handelt. Das Gleiche gilt für System.err. Diese Dateien tragen die Nummern (bzw. descripteur) 1 bzw. 2. Der Eingabestrom von der Tastatur (System.in) wird ebenfalls als Textdatei mit dem Deskriptor 0 betrachtet. Sowohl DOS als auch Unix unterstützen die Befehlsverknüpfung (Pipe):

    commande1 | commande2

Alles, was commande1 mit System.out schreibt, wird an den Eingang System.in von commande2 weitergeleitet. Anders ausgedrückt: commande2 liest mit System.in die Daten, die von commande2 mit System.out erzeugt wurden und daher nicht mehr auf dem Bildschirm angezeigt werden. Dieses System wird unter Unix häufig verwendet. In dieser Pipe wird der Datenstrom von System.err hingegen nicht umgeleitet: Er schreibt auf den Bildschirm. Deshalb wird er zum Ausgeben von Fehlermeldungen verwendet (daher auch sein Name err): So ist sichergestellt, dass bei einer Befehlsweiterleitung die Fehlermeldungen weiterhin auf dem Bildschirm angezeigt werden. Man sollte sich daher angewöhnen, Fehlermeldungen mit dem Datenstrom System.err auf den Bildschirm zu schreiben, anstatt mit dem Datenstrom System.out.

2.3.2. Auslesen von über die Tastatur eingegebenen Daten

Der Datenstrom von der Tastatur wird durch das Objekt System.in vom Typ InputStream bezeichnet. Dieser Objekttyp ermöglicht das Einlesen von Daten Zeichen für Zeichen. Es ist Aufgabe des Programmierers, anschließend in diesem Zeichenstrom die für ihn relevanten Informationen zu finden. Der Typ InputStream ermöglicht es nicht, eine Textzeile auf einmal einzulesen. Der Typ BufferedReader ermöglicht dies mit der Methode readLine.

Um über die Tastatur eingegebene Textzeilen lesen zu können, wird aus dem Eingabestrom System.in vom Typ InputStream ein weiterer Eingabestrom erstellt, diesmal vom Typ BufferedReader:

BufferedReader IN=new BufferedReader(new InputStreamReader(System.in));

Wir werden hier nicht auf die Details dieser Anweisung eingehen, die den Begriff der Objektkonstruktion beinhaltet. Wir werden sie so verwenden, wie sie ist.

Die Erstellung eines Streams kann fehlschlagen: In diesem Fall wird ein schwerwiegender Fehler, in Java als „Ausnahme“ bezeichnet, ausgelöst. Immer wenn eine Methode eine Ausnahme auslösen kann, verlangt der Java-Compiler, dass diese vom Programmierer abgefangen wird. Um den oben genannten Eingabestream zu erstellen, muss daher tatsächlich folgender Code geschrieben werden:


BufferedReader IN=null;
try{
IN=new BufferedReader(new InputStreamReader(System.in));
} catch (Exception e){
        System.err.println("Erreur " +e);
        System.exit(1);
}

Auch hier soll die Ausnahmebehandlung nicht näher erläutert werden. Sobald der vorherige Datenstrom IN aufgebaut ist, kann mit der Anweisung eine Textzeile gelesen werden:

    String ligne;
    ligne=IN.readLine();

Die über die Tastatur eingegebene Zeile wird in der Variablen ligne gespeichert und kann anschließend vom Programm weiterverarbeitet werden.

2.3.3. Beispiel für Ein- und Ausgabe

Hier ist ein Programm zur Veranschaulichung der Ein- und Ausgabeoperationen über Tastatur und Bildschirm:


import java.io.*;        // erforderlich für die Verwendung von E/A-Streams

public class io1{
  
  
  public static void main (String[] arg){
    
    // Schreiben in den Stream System.out
    Object obj=new Object();
    System.out.println(""+obj);
    System.out.println(obj.getClass().getName());
    
    // Schreiben in den Datenstrom System.err
    int i=10;
    System.err.println("i="+i);
    
    // Lesen einer über die Tastatur eingegebenen Zeile
    String ligne;
    BufferedReader IN=null;
    try{
      IN=new BufferedReader(new InputStreamReader(System.in));
    } catch (Exception e){
      affiche(e);
      System.exit(1);
    }
    System.out.print("Tapez une ligne : ");
    try{
      ligne=IN.readLine();
      System.out.println("ligne="+ligne);
    } catch (Exception e){
      affiche(e);
      System.exit(2);
    }
  }//Ende der Eingabe

  public static void affiche(Exception e){
    System.err.println("Erreur : "+e);
  }

}//Ende der Klasse

und die Ergebnisse der Ausführung:

C:\Serge\java\bases\iostream>java io1
java.lang.Object@1ee78b
java.lang.Object
i=10
Tapez une ligne : je suis là
ligne=je suis là

Die Anweisungen

Object obj=new Object();
System.out.println(""+obj);
System.out.println(obj.getClass().getName());

sollen zeigen, dass jedes beliebige Objekt angezeigt werden kann. Wir werden hier nicht näher auf die Bedeutung der angezeigten Inhalte eingehen. Außerdem wird im folgenden Block der Wert eines Objekts angezeigt:

try{
      IN=new BufferedReader(new InputStreamReader(System.in));
    } catch (Exception e){
      affiche(e);
      System.exit(1);
    }

Die Variable e ist ein Objekt vom Typ Exception, das hier mit dem Aufruf affiche(e) angezeigt wird. Wir sind dieser Anzeige des Werts einer Ausnahme bereits im oben gezeigten Konvertierungsprogramm begegnet, ohne darauf einzugehen.

2.3.4. Zuweisung des Werts eines Ausdrucks an eine Variable

Wir befassen uns hier mit der Operation variable=expression;

Der Ausdruck kann folgender Art sein: arithmetisch, relational, boolesch, Zeichen

2.3.4.1. Interpretation der Zuweisungsoperation

Die Operation variable=expression; ist selbst ein Ausdruck, dessen Auswertung wie folgt abläuft:

  • Die rechte Seite der Zuweisung wird ausgewertet: Das Ergebnis ist ein Wert V.
  • Der Wert V wird der Variablen zugewiesen
  • Der Wert V ist zugleich der Wert der Zuweisung, die nun als Ausdruck betrachtet wird.

Daher ist die Operation V1=V2=Ausdruck zulässig ist. Aufgrund der Priorität wird der Operand „=“ ganz rechts ausgewertet. Wir erhalten also V1=(V2=Ausdruck). Der Ausdruck V2=Ausdruck wird ausgewertet und ergibt den Wert V. Die Auswertung dieses Ausdrucks führte dazu, dass V an V2 zugewiesen wurde. Der nächste Operator „=“ wird dann in der Form V1=V ausgewertet. Der Wert dieses Ausdrucks ist wiederum V. Seine Auswertung führt zur Zuweisung von V an V1. Somit ist die Operation V1=V2=Ausdruck ist ein Ausdruck, dessen Auswertung

1: die Zuweisung des Wertes von expression an die Variablen V1 und V2 bewirkt

2: den Wert von expression als Ergebnis liefert.

Man kann dies auf einen Ausdruck der folgenden Form verallgemeinern: V1 = V2 = ... = Vn = Ausdruck

2.3.4.2. Arithmetischer Ausdruck

Die Operatoren für arithmetische Ausdrücke sind folgende:

+: Addition

  • : Subtraktion

*: Multiplikation

/: Division: Das Ergebnis ist der exakte Quotient, wenn mindestens einer der Operanden reell ist. Sind beide Operanden ganzzahlig, ist das Ergebnis der ganzzahlige Quotient. Somit ergibt 5/2 -> 2 und 5,0/2 -> 2,5.

% : Division: Das Ergebnis ist der Rest, unabhängig von der Art der Operanden, wobei der Quotient ganzzahlig ist. Es handelt sich also um die Modulo-Operation.

Es gibt verschiedene mathematische Funktionen:

double sqrt(double x)
Quadratwurzel
double cos(double x)
Kosinus
double sin(double x)
Sinus
double tan(double x)
Tangens
double pow(double x, double y)
x hoch y (x > 0)
double exp(double x)
Exponentialfunktion
double log(double x)
natürlicher Logarithmus
double abs(double x)
Absolutwert

usw.

Alle diese Funktionen sind in einer Java-Klasse namens „Math“ definiert. Bei ihrer Verwendung muss ihnen der Name der Klasse vorangestellt werden, in der sie definiert sind. Man schreibt also:

double x, y=4;
x=Math.sqrt(y);

Die Definition der Klasse Math lautet wie folgt:


public  final  class  java.lang.Math
    extends  java.lang.Object  (I-§1.12)
{
        // Felder
    public final static double E;    §1.10.1
    public final static double PI;    §1.10.2

        // Methoden
    public static double abs(double  a);    §1.10.3
    public static float abs(float  a);    §1.10.4
    public static int abs(int  a);    §1.10.5
    public static long abs(long  a);    §1.10.6
    public static double acos(double  a);    §1.10.7
    public static double asin(double  a);    §1.10.8
    public static double atan(double  a);    §1.10.9
    public static double atan2(double  a, double  b);    §1.10.10
    public static double ceil(double  a);    §1.10.11
    public static double cos(double  a);    §1.10.12
    public static double exp(double  a);    §1.10.13
    public static double floor(double  a);    §1.10.14
    public static double                        §1.10.15
        IEEEremainder(double  f1, double  f2);
    public static double log(double  a);    §1.10.16
    public static double max(double  a, double  b);    §1.10.17
    public static float max(float  a, float  b);    §1.10.18
    public static int max(int  a, int  b);    §1.10.19
    public static long max(long  a, long  b);    §1.10.20
    public static double min(double  a, double  b);     §1.10.21
    public static float min(float  a, float  b);    §1.10.22
    public static int min(int  a, int  b);    §1.10.23
    public static long min(long  a, long  b);    §1.10.24
    public static double pow(double  a, double  b);    §1.10.25
    public static double random();    §1.10.26
    public static double rint(double  a);    §1.10.27
    public static long round(double  a);    §1.10.28
    public static int round(float  a);    §1.10.29
    public static double sin(double  a);    §1.10.30
    public static double sqrt(double  a);    §1.10.31
    public static double tan(double  a);    §1.10.32
}

2.3.4.3. Prioritäten bei der Auswertung arithmetischer Ausdrücke

Die Priorität der Operatoren bei der Auswertung eines arithmetischen Ausdrucks ist wie folgt (von der höchsten zur niedrigsten Priorität):

[fonctions], [ ( )], [ *, /, %], [+, -]

Operatoren innerhalb desselben Blocks [ ] haben dieselbe Priorität.

2.3.4.4. Relationale Ausdrücke

Es gibt folgende Operatoren: <, <=, ==, !=, >, >=

Prioritätsreihenfolge

>, >=, <, <=

==, !=

Das Ergebnis eines relationalen Ausdrucks ist der Boolesche Wert false, wenn der Ausdruck falsch ist, andernfalls true.

Beispiel:

      boolean fin;
      int x;
      fin=x>4;

Vergleich zweier Zeichen

Gegeben seien zwei Zeichenfolgen C1 und C2. Diese können mit den Operatoren

<, <=, ==, !=, >, >=

Es werden dann ihre Codes ASCII, bei denen es sich um Zahlen handelt, miteinander verglichen. Zur Erinnerung: Gemäß der Reihenfolge ASCII gelten die folgenden Beziehungen:

Leerzeichen < .. < '0' < '1' < .. < '9' < .. < 'A' < 'B' < .. < 'Z' < .. < 'a' < 'b' < .. < 'z'

Vergleich zweier Zeichenketten

Sie werden Zeichen für Zeichen verglichen. Die erste Ungleichheit, die zwischen zwei Zeichen auftritt, führt zu einer Ungleichheit gleicher Richtung bei den Zeichenketten.

Beispiele:

Vergleichen wir die Zeichenfolgen „Chat“ und „Chien“

Diese letzte Ungleichheit lässt den Schluss zu, dass „Katze“ < „Hund“ gilt.

Image

Nehmen wir an, wir wollen die Zeichenfolgen „Katze“ und „Kätzchen“ vergleichen. Es herrscht durchgehend Gleichheit, bis die Zeichenfolge „Katze“ vollständig abgearbeitet ist. In diesem Fall wird die vollständig abgearbeitete Zeichenfolge als die „kleinere“ deklariert. Es gilt also die Beziehung

„Katze“ < „Kätzchen“.

Funktionen zum Vergleich zweier Zeichenfolgen

Die relationalen Operatoren <, <=, ==, !=, >, >= können hier nicht verwendet werden. Es müssen Methoden der Klasse String verwendet werden:

String chaine1, chaine2;
chaine1=;
chaine2=;
int i=chaine1.compareTo(chaine2);
boolean egal=chaine1.equals(chaine2)

Im obigen Beispiel hat die Variable i folgenden Wert:

0: wenn beide Zeichenfolgen gleich sind

1: wenn Zeichenfolge Nr. 1 > Zeichenfolge Nr. 2

-1: wenn Zeichenfolge Nr. 1 < Zeichenfolge Nr. 2

Die Variable egal nimmt den Wert true an, wenn die beiden Zeichenfolgen gleich sind.

2.3.4.5. Boolesche Ausdrücke

Die Operatoren sind & (and) ||(or) und ! (not). Das Ergebnis eines booleschen Ausdrucks ist ein Boolescher Wert.

Prioritätsreihenfolge ! , &&, ||

Beispiel:

int fin;
int x;
fin= x>2 && x<4;

Relationale Operatoren haben Vorrang vor den Operatoren && und ||.

2.3.4.6. Bitweise Verarbeitung

Die Operatoren

Seien i und j zwei ganze Zahlen.

i<<n
verschiebt i um n Bits nach links. Die eingehenden Bits sind Nullen.
i>>n
verschiebt i um n Bits nach rechts. Ist i eine vorzeichenbehaftete Ganzzahl (signed char, int, long), bleibt das Vorzeichenbit erhalten.
i & j
führt die bitweise logische ODER-Verknüpfung von i und j durch.
i | j
führt die bitweise logische ODER-Verknüpfung von i und j durch.
~i
ergänzt i auf 1
i^j
Erzeugt OU aus EXCLUSIF von i und j

Das heißt

    int i=0x123F, k=0xF123;
    unsigned j=0xF123;
Operation
Wert
i<<4
0x23F0
i>>4
0x0123 Das Vorzeichenbit bleibt erhalten.
k>>4
0xFF12 Das Vorzeichenbit bleibt erhalten.
i&j
0x1023
i|j
0xF33F
~i
0xEDC0

2.3.4.7. Kombination von Operatoren

a=a+b lässt sich als a+=b schreiben

a=a-b kann als a-=b geschrieben werden

Das Gleiche gilt für die Operatoren /, %, *, <<, >>, &, |, ^

So lässt sich beispielsweise a=a+2; als a+=2; schreiben

2.3.4.8. Inkrementierungs- und Dekrementierungsoperatoren

Die Schreibweise variable++ bedeutet variable=variable+1 oder auch variable+=1

Die Schreibweise variable-- bedeutet variable=variable-1 oder auch variable-=1.

2.3.4.9. Der Operator ?

Der Ausdruck expr_cond ? expr1:expr2 wird wie folgt ausgewertet:

1: Der Ausdruck expr_cond wird ausgewertet. Es handelt sich um einen bedingten Ausdruck, dessen Wert entweder „wahr“ oder „falsch“ ist

2: Ist er wahr, ist der Wert des Ausdrucks der von expr1. expr2 wird nicht ausgewertet.

3: Ist die Bedingung falsch, geschieht das Gegenteil: Der Wert des Ausdrucks ist der Wert von expr2. expr1 wird nicht ausgewertet.

Beispiel

i = (j > 4 ? j + 1 : j - 1);

wird der Variablen i zugewiesen:

j+1, wenn j>4, andernfalls j-1

Das entspricht dem Ausdruck if(j>4) i=j+1; else i=j-1;, ist jedoch prägnanter.

2.3.4.10. Allgemeine Operatorpriorität

() [] Funktion
gd
! ~ ++ --
dg
new (Typ) Cast-Operatoren
dg
* / %
gd
+ -
gd
<< >>
gd
< <= > >= instanceof
gd
== !=
gd
&
gd
^
gd
|
gd
&&
gd
||
gd
? :
dg
= += -= usw. .
dg

gd: Gibt an, dass bei gleicher Priorität die Priorität von links nach rechts gilt. Das bedeutet, dass in einem Ausdruck, in dem Operatoren gleicher Priorität vorkommen, der Operator ganz links im Ausdruck zuerst ausgewertet wird. dg gibt eine Priorität von rechts nach links an.

2.3.4.11. Typumwandlungen

In einem Ausdruck ist es möglich, die Darstellung eines Wertes vorübergehend zu ändern. Dies wird als Typumwandlung oder im Englischen als „type casting“ bezeichnet. Die Syntax für die Typumwandlung eines Wertes in einem Ausdruck lautet: (Typ) Wert. Der Wert nimmt dann den angegebenen Typ an. Dies führt zu einer Änderung der Darstellung des Wertes.

Beispiel:

int i, j;
float isurj;
isurj= (float)i/j;   // Priorität von () gegenüber /

Hier muss der Typ von i oder j in „real“ geändert werden, da die Division sonst einen ganzzahligen und keinen reellen Quotienten ergibt.

i ist ein exakt auf 2 Byte codierter Wert

(float) i ist derselbe Wert, der als Gleitkommazahl über 4 Bytes approximativ kodiert ist

Es findet also eine Umkodierung des Werts von i statt. Diese Umkodierung erfolgt nur für die Dauer einer Berechnung, wobei die Variable i stets ihren Typ int beibehält.

2.4. Anweisungen zur Steuerung des Programmablaufs

2.4.1. Beenden

Mit der in der Klasse System definierten Methode exit kann die Ausführung eines Programms abgebrochen werden.

Syntax : void exit(int status)

Funktion: Beendet den laufenden Prozess und gibt den Wert „status“ an den übergeordneten Prozess zurück

exit bewirkt die Beendigung des laufenden Prozesses und übergibt die Kontrolle an den aufrufenden Prozess. Der Wert von status kann von diesem verwendet werden. Unter DOS wird diese Variable status an DOS in der Systemvariablen ERRORLEVEL zurückgegeben, deren Wert in einer Batch-Datei überprüft werden kann. Unter Unix übernimmt die Variable $? den Wert von status, wenn die Befehlszeilen-Interpreter die Bourne-Shell (/bin/sh) ist.

Beispiel:

    System.exit(0);

um das Programm mit einem Statuswert von 0 zu beenden.

2.4.2. Einfache Entscheidungsstruktur


 syntaxe :  if (condition) {actions_condition_vraie;} else {actions_condition_fausse;}

Hinweise:

  • Die Bedingung steht in Klammern.
  • Jede Aktion endet mit einem Semikolon.
  • Die geschweiften Klammern werden nicht mit einem Semikolon abgeschlossen.
  • Geschweifte Klammern sind nur erforderlich, wenn mehr als eine Aktion vorhanden ist.
  • Die else-Klausel kann weggelassen werden.
  • Es gibt kein „then“.

Das algorithmische Äquivalent dieser Struktur ist die if-then-else-Struktur:

si condition
  alors actions_condition_vraie
  sinon actions_conditions_fausse
finsi

Beispiel


    if (x>0)  { nx=nx+1;sx=sx+x;} else dx=dx-x;

Auswahlstrukturen können verschachtelt werden:

if(condition1)
if (condition2)
        {......}
      else         //Bedingung2
         {......}
else         //Bedingung1
     {.......}

Manchmal tritt folgendes Problem auf:


public static void main(void){
      int n=5;

   if(n>1)
     if(n>6)
             System.out.println(">6");
     else System.out.println("<=6");
}

Auf welches if bezieht sich im vorigen Beispiel das else? Die Regel lautet, dass sich ein else immer auf das nächstgelegene if bezieht: im Beispiel also auf if(n>6). Betrachten wir ein weiteres Beispiel:


public static void main(void)
{  int n=0;

   if(n>1)
     if(n>6)   System.out.println(">6");
     else;            // else des if(n>6): nichts zu tun 
   else System.out.println("<=1");    // else der if(n>1) 
}

Hier wollten wir ein else an das if(n>1) anhängen und kein else an das if(n>6). Aufgrund der vorherigen Anmerkung sind wir gezwungen, ein „else“ für if(n>6) einzufügen, in dem sich keine Anweisung befindet.

2.4.3. Fallstruktur

Die Syntax lautet wie folgt:

switch(expression) {
    case v1:     
            actions1;
            break;
    case v2:     
            actions2;
            break;
         . .. .. .. .. ..
    default:     actions_sinon;
}

Hinweise

  • Der Wert des Steuerausdrucks darf nur eine ganze Zahl oder ein Zeichen sein.
  • Der Steuerausdruck steht in Klammern.
  • Die Klausel default kann fehlen.
  • Die Werte vi sind mögliche Werte des Ausdrucks. Wenn der Ausdruck den Wert vi hat, werden die Aktionen hinter der case-Klausel vi ausgeführt.
  • Die Anweisung break verlässt die case-Struktur. Fehlt sie am Ende des Anweisungsblocks mit dem Wert vi, wird die Ausführung mit den Anweisungen des Werts vi+1 fortgesetzt.

Beispiel

In der Algorithmik

selon la valeur de choix
cas 0
          arrêt
      cas 1
    exécuter module M1
  cas 2
    exécuter module M2
  sinon
    erreur<--vrai
findescas

In Java


    int choix, erreur;
    switch(choix){   
        case 0: System.exit(0);
      case 1: M1();break;
      case 2: M2();break;
      default: erreur=1;
     }

2.4.4. Wiederholungsstruktur

2.4.4.1. Anzahl der Wiederholungen bekannt

Syntax


    for (i=id;i<=if;i=i+ip){ 
       actions; 
      } 

Hinweise

  • Die drei Argumente von for stehen in Klammern.
  • Die drei Argumente von for sind durch Semikolons getrennt.
  • Jede Aktion von for endet mit einem Semikolon.
  • Die geschweifte Klammer ist nur erforderlich, wenn mehr als eine Aktion vorhanden ist.
  • Auf die geschweifte Klammer folgt kein Semikolon.

Das algorithmische Äquivalent ist die Struktur pour:

pour i variant de id à if avec un pas de ip
        actions
finpour

was sich in eine Struktur tantque übersetzen lässt:

    i  id
    tantque i<=if
        actions
        i i+ip
    fintantque

2.4.4.2. Anzahl der Wiederholungen unbekannt

In Java gibt es zahlreiche Strukturen für diesen Fall.

„while“-Schleife


    while(condition){
          actions;
        } 

Die Schleife wird so lange ausgeführt, wie die Bedingung erfüllt ist. Es kann sein, dass die Schleife nie ausgeführt wird.

Hinweise:

  • Die Bedingung steht in Klammern.
  • Jede Aktion wird mit einem Semikolon abgeschlossen.
  • Die geschweifte Klammer ist nur erforderlich, wenn mehr als eine Aktion vorhanden ist.
  • Auf die geschweifte Klammer folgt kein Semikolon.

Die entsprechende algorithmische Struktur ist die „solange“-Struktur:

tantque condition
        actions
fintantque

„Wiederhole, bis“-Struktur (do while)

Die Syntax lautet wie folgt:


    do{
       instructions;
    }while(condition); 

Die Schleife wird so lange wiederholt, bis die Bedingung falsch wird oder solange die Bedingung wahr ist. Hier wird die Schleife mindestens einmal durchlaufen.

Hinweise

  • Die Bedingung steht in Klammern.
  • Jede Aktion wird mit einem Semikolon abgeschlossen.
  • Die geschweifte Klammer ist nur erforderlich, wenn mehr als eine Aktion vorhanden ist.
  • Auf die geschweifte Klammer folgt kein Semikolon.

Die entsprechende algorithmische Struktur ist die „Wiederhole … bis“-Struktur:

répéter
    actions
jusqu'à condition

Struktur für „for“

Die Syntax lautet wie folgt:


for(instructions_départ;condition;instructions_fin_boucle){
    instructions; 
}

Die Schleife wird so lange durchlaufen, wie die Bedingung wahr ist (sie wird vor jedem Schleifendurchlauf ausgewertet). Instructions_départ werden vor dem ersten Eintritt in die Schleife ausgeführt. Instructions_fin_boucle werden nach jedem Schleifendurchlauf ausgeführt.

Anmerkungen

  • Die drei Argumente von for stehen in Klammern.
  • Die drei Argumente von for sind durch Semikolons getrennt.
  • Jede Aktion der for-Schleife endet mit einem Semikolon.
  • Die geschweifte Klammer ist nur erforderlich, wenn mehr als eine Aktion vorhanden ist.
  • Auf die geschweifte Klammer folgt kein Semikolon.
  • Die verschiedenen Anweisungen in instructions_depart und instructions_fin_boucle sind durch Kommas getrennt.

Die entsprechende algorithmische Struktur sieht wie folgt aus:

instructions_départ
tantque condition
        actions
        instructions_fin_boucle
fintantque

Beispiele

Die folgenden Programme berechnen alle die Summe der ersten n ganzen Zahlen.


1  for(i=1, somme=0;i<=n;i=i+1)
        somme=somme+a[i];

2     for (i=1, somme=0;i<=n;somme=somme+a[i], i=i+1);

3    i=1;somme=0;
    while(i<=n)
       { somme+=i; i++; }

4    i=1; somme=0;
    do somme+=i++;
         while (i<=n);

Anweisungen zur Schleifenverwaltung

break
Beendet die Schleife „for“, „while“ oder „do ... while“.
continue
springt zur nächsten Iteration der Schleifen „for“, „while“ und „do ... while“

2.5. Die Struktur eines Java-Programms

Ein Java-Programm, das weder benutzerdefinierte Klassen noch andere Funktionen als die Hauptfunktion main verwendet, kann folgende Struktur haben:


public class test1{
    public static void main(String arg[]){
        … code du programme
    }// main
}// Klasse

Die Funktion main, auch Methode genannt, wird bei der Ausführung eines Java-Programms als Erstes aufgerufen. Sie muss zwingend die folgende Signatur aufweisen:


    public static void main(String arg[]){

oder


    public static void main(String[] arg){

Der Name des Arguments arg kann beliebig sein. Es handelt sich um ein Array von Zeichenketten, die die Argumente der Befehlszeile darstellen. Wir werden später noch darauf zurückkommen.

Wenn Funktionen verwendet werden, die Ausnahmen erzeugen können, die nicht detailliert behandelt werden sollen, kann der Programmcode mit einer try/catch-Klausel umschlossen werden:


public class test1{
    public static void main(String arg[]){
        try{
        … code du programme
        } catch (Exception e){
            // Fehlerbehandlung
        }// try
    }// main
}// Klasse

Am Anfang des Quellcodes und vor der Klassendefinition finden sich üblicherweise Anweisungen zum Importieren von Klassen. Zum Beispiel:


import java.io.*;
public class test1{
    public static void main(String arg[]){
        … code du programme
    }// main
}// Klasse

Nehmen wir ein Beispiel. Angenommen, es gibt folgende Schreibanweisung:

System.out.println("java");

die java auf den Bildschirm schreibt. In diesem einfachen Befehl steckt eine Menge:

  • System ist eine Klasse, deren vollständiger Name java.lang.System lautet
  • out ist eine Eigenschaft dieser Klasse vom Typ java.io.PrintStream, einer weiteren Klasse
  • println ist eine Methode der Klasse java.io.PrintStream.

Wir wollen diese Erklärung nicht unnötig verkomplizieren, da sie zu früh kommt und das Verständnis des Begriffs „Klasse“ voraussetzt, der noch nicht behandelt wurde. Eine Klasse lässt sich mit einer Ressource vergleichen. In diesem Fall benötigt der Compiler Zugriff auf die beiden Klassen java.lang.System und java.io.PrintStream. Die Hunderte von Java-Klassen sind in Archiven verteilt, die auch als Pakete (Packages) bezeichnet werden. Die am Anfang des Programms platzierten Anweisungen import dienen dazu, dem Compiler mitzuteilen, welche externen Klassen das Programm benötigt (d. h. diejenigen, die verwendet, aber nicht in der zu kompilierenden Quelldatei definiert sind). In unserem Beispiel benötigt unser Programm also die Klassen java.lang.System und java.io.PrintStream. Dies wird mit der Anweisung import angegeben. Am Anfang des Programms könnte man schreiben:

import java.lang.System;
import java.io.PrintStream;

Da ein Java-Programm üblicherweise mehrere Dutzend externe Klassen verwendet, wäre es mühsam, alle erforderlichen Funktionen import zu schreiben. Die Klassen wurden in Paketen zusammengefasst, sodass man das gesamte Paket importieren kann. Um also die Pakete java.lang und java.io zu importieren, schreibt man:

import java.lang.*;
import java.io.*;

Das Paket java.lang enthält alle Java-Basisklassen und wird vom Compiler automatisch importiert. Daher schreibt man letztendlich nur:

import java.io.*;

2.6. Ausnahmebehandlung

Viele Java-Funktionen können Ausnahmen, d. h. Fehler, auslösen. Wir sind bereits auf eine solche Funktion gestoßen, nämlich die Funktion readLine:


String ligne=null;
try{
      ligne=IN.readLine();
      System.out.println("ligne="+ligne);
    } catch (Exception e){
      affiche(e);
      System.exit(2);
}// try

Wenn eine Funktion eine Ausnahme auslösen kann, zwingt der Java-Compiler den Programmierer, diese zu behandeln, um fehlerresistentere Programme zu erhalten: Ein unkontrollierter „Absturz“ einer Anwendung muss stets vermieden werden. Hier löst die Funktion readLine eine Ausnahme aus, wenn nichts zu lesen ist, weil beispielsweise der Eingabestrom geschlossen wurde. Die Behandlung einer Ausnahme erfolgt nach folgendem Schema:

try{
    appel de la fonction susceptible de générer l'exception
} catch (Exception e){
    traiter l'exception e
}
instruction suivante

Wenn die Funktion keine Ausnahme auslöst, wird zur nächsten Anweisung übergegangen; andernfalls wird in den Hauptteil der Klausel catch verzweigt und anschließend zur nächsten Anweisung übergegangen. Beachten Sie folgende Punkte:

  • e ist ein abgeleitetes Objekt vom Typ Exception. Man kann genauer sein, indem man Typen wie IOException, SecurityException, ArithmeticException usw. verwendet: Es gibt etwa zwanzig Ausnahmetypen. Mit der Anweisung „catch (Exception e)“ gibt man an, dass alle Ausnahmetypen abgefangen werden sollen. Wenn der Code der Klausel try mehrere Ausnahmetypen auslösen kann, möchte man möglicherweise genauer vorgehen und die Ausnahme mit mehreren Klauseln vom Typ catch abfangen:

try{
    appel de la fonction susceptible de générer l'exception
} catch (IOException e){
    traiter l'exception e
}
} catch (ArrayIndexOutOfBoundsException e){
    traiter l'exception e
}
} catch (RunTimeException e){
    traiter l'exception e
}
instruction suivante
  • Den Klauseln try/catch kann eine finally-Klausel hinzugefügt werden:
try{
    appel de la fonction susceptible de générer l'exception
} catch (Exception e){
    traiter l'exception e
}
finally{
    code exécuté après try ou catch
}
instruction suivante

Unabhängig davon, ob eine Ausnahme vorliegt oder nicht, wird der Code der Klausel finally immer ausgeführt.

  • Die Klasse Exception verfügt über eine Methode getMessage(), die eine Meldung zurückgibt, in der der aufgetretene Fehler detailliert beschrieben wird. Wenn man diesen anzeigen möchte, schreibt man also:
catch (Exception ex){
    System.err.println("L'erreur suivante s'est produite : "+ex.getMessage());
    ...
}//catch
  • Die Klasse Exception verfügt über eine Methode toString(), die eine Zeichenkette zurückgibt, die den Typ der Ausnahme sowie den Wert der Eigenschaft Message angibt. Man kann also schreiben:
catch (Exception ex){
    System.err.println ("L'erreur suivante s'est produite : "+ex.toString());
    ...
}//catch

Man kann auch schreiben:

catch (Exception ex){
    System.err.println ("L'erreur suivante s'est produite : "+ex);
    ...
}//catch

Hier handelt es sich um eine Operation vom Typ „Zeichenkette + Exception“, die vom Compiler automatisch in „Zeichenkette + Exception.toString()“ umgewandelt wird, um die Verkettung zweier Zeichenketten durchzuführen.

Das folgende Beispiel zeigt eine Ausnahme, die durch die Verwendung eines nicht vorhandenen Array-Elements ausgelöst wird:

// Tabellen

// Importe
import java.io.*;

public class tab1{
  public static void main(String[] args){
    // Deklaration und Initialisierung eines Arrays
    int[] tab=new int[] {0,1,2,3};
    int i;
     // Anzeige eines Arrays mit einer for-Schleife
    for (i=0; i<tab.length; i++)
      System.out.println("tab[" + i + "]=" + tab[i]);
    // Auslösen einer Ausnahme
      try{
      tab[100]=6;
    }catch (Exception e){
      System.err.println("L'erreur suivante s'est produite : " + e);
    }//try-catch
  }//main
}//Klasse

Die Ausführung des Programms liefert folgende Ergebnisse:

tab[0]=0
tab[1]=1
tab[2]=2
tab[3]=3
L'erreur suivante s'est produite : java.lang.ArrayIndexOutOfBoundsException

Hier ist ein weiteres Beispiel, in dem die Ausnahme behandelt wird, die durch die Zuweisung einer Zeichenkette zu einer Zahl ausgelöst wird, wenn die Zeichenkette keine Zahl darstellt:

// Importe
import java.io.*;

public class console1{
  public static void main(String[] args){
      // Erstellung eines Eingabestroms
    BufferedReader IN=null;
    try{
        IN=new BufferedReader(new InputStreamReader(System.in));
    }catch(Exception ex){}
     // Der Name wird abgefragt
    System.out.print("Nom : ");
     // Antwort lesen
    String nom=null;
    try{
        nom=IN.readLine();
    }catch(Exception ex){}      
     // Nach dem Alter wird gefragt
    int age=0;
    boolean ageOK=false;
    while ( ! ageOK){
       // Frage
      System.out.print("âge : ");
       // Antwort lesen und überprüfen
      try{
        age=Integer.parseInt(IN.readLine());
        ageOK=true;
      }catch(Exception ex) {
        System.err.println("Age incorrect, recommencez...");
      }//try-catch
    }//while
     // Abschließende Anzeige
    System.out.println("Vous vous appelez " + nom + " et vous avez " + age + " ans");
  }//Main
}//Klasse

Einige Ausführungsergebnisse:

dos>java console1
Nom : dupont
âge : 23
Vous vous appelez dupont et vous avez 23 ans
E:\data\serge\MSNET\c#\bases\1>console1
Nom : dupont
âge : xx
Age incorrect, recommencez...
âge : 12
Vous vous appelez dupont et vous avez 12 ans

2.7. Kompilieren und Ausführen eines Java-Programms

Kompilieren und führen Sie das folgende Programm aus:

// Import von Klassen
import java.io.*;

// Testklasse
public class coucou{
    // Hauptfunktion
  public static void main(String args[]){
      // Bildschirmanzeige
    System.out.println("coucou");
  }//main
}//Klasse

Die Quelldatei, die die vorherige Klasse coucou enthält, muss zwingend den Namen coucou.java tragen:

E:\data\serge\JAVA\ESSAIS\intro1>dir
10/06/2002  08:42                  228 coucou.java

Die Kompilierung und Ausführung eines Java-Programms erfolgt in einem Fenster mit der Bezeichnung DOS. Die ausführbaren Dateien javac.exe (Compiler) und java.exe (Interpreter) befinden sich im Verzeichnis bin des Installationsverzeichnisses von JDK:

E:\data\serge\JAVA\classes\paquetages\personne>dir "e:\program files\jdk14\bin\java?.exe"
07/02/2002  12:52               24 649 java.exe
07/02/2002  12:52               28 766 javac.exe

Der Compiler javac.exe analysiert die .java-Quelldatei und erzeugt eine kompilierte .class-Datei. Diese kann vom Prozessor nicht sofort ausgeführt werden. Sie benötigt einen Java-Interpreter (java.exe), der als virtuelle Maschine oder JVM (Java Virtual Machine) bezeichnet wird. Ausgehend vom Zwischencode in der .class-Datei generiert die virtuelle Maschine Befehle, die für den Prozessor des Computers, auf dem sie ausgeführt wird, spezifisch sind. Es gibt Java-Virtual-Machines für verschiedene Betriebssysteme (Windows, Unix, Mac OS, ...). Eine .class-Datei kann von jeder dieser Virtual Machines und somit auf jedem Betriebssystem ausgeführt werden. Diese systemübergreifende Portabilität ist einer der größten Vorteile von Java.

Kompilieren wir das vorherige Programm:

E:\data\serge\JAVA\ESSAIS\intro1>"e:\program files\jdk14\bin\javac" coucou.java

E:\data\serge\JAVA\ESSAIS\intro1>dir
10/06/2002  08:42                  228 coucou.java
10/06/2002  08:48                  403 coucou.class

Führen wir die erzeugte Datei .class aus:

E:\data\serge\JAVA\ESSAIS\intro1>"e:\program files\jdk14\bin\java" coucou
coucou

Es ist zu beachten, dass in dem obigen Ausführungsbefehl das Suffix .class der auszuführenden Datei coucou.class nicht angegeben wurde. Es ist implizit enthalten. Befindet sich das Verzeichnis „bin“ der Datei „JDK“ im Verzeichnis „PATH“ des Rechners „DOS“, muss der vollständige Pfad zu den ausführbaren Dateien javac.exe und java.exe nicht angegeben werden. Man schreibt dann einfach

javac coucou.java
java coucou

2.8. Argumente des Hauptprogramms

Die Hauptfunktion main akzeptiert als Parameter ein String-Array: String[]. Dieses Array enthält die Argumente der Befehlszeile, mit der die Anwendung gestartet wurde. Wenn also das Programm P mit dem folgenden Befehl gestartet wird:

        java P arg0 arg1 … argn

und die Funktion „main“ wie folgt deklariert ist:

public static void main(String[] arg);

erhält man arg[0]="arg0", arg[1]="arg1" … Hier ein Beispiel:


import java.io.*;

public class param1{
  public static void main(String[] arg){
    int i;
    System.out.println("Nombre d'arguments="+arg.length);
    for (i=0;i<arg.length;i++)
      System.out.println("arg["+i+"]="+arg[i]);
  }
}

Die folgenden Ergebnisse wurden erzielt:

dos>java param1 a b c
Nombre d'arguments=3
arg[0]=a
arg[1]=b
arg[2]=c

2.9. Übergabe von Parametern an eine Funktion

Die vorangegangenen Beispiele zeigten ausschließlich Java-Programme mit nur einer Funktion, nämlich der Hauptfunktion main. Das folgende Beispiel veranschaulicht, wie Funktionen verwendet werden und wie der Informationsaustausch zwischen Funktionen erfolgt. Die Parameter einer Funktion werden immer als Wert übergeben: Das bedeutet, dass der Wert des tatsächlichen Parameters in den entsprechenden formalen Parameter kopiert wird.


import java.io.*;

public class param2{
  public static void main(String[] arg){
    String S="papa";
    changeString(S);
    System.out.println("Paramètre effectif S="+S);
    int age=20;
    changeInt(age);
    System.out.println("Paramètre effectif age="+age);
  }
  private static void changeString(String S){
    S="maman";
    System.out.println("Paramètre formel S="+S);
  }
  private static void changeInt(int a){
    a=30;
    System.out.println("Paramètre formel a="+a);
  }
}

Die folgenden Ergebnisse wurden erzielt:

Paramètre formel S=maman
Paramètre effectif S=papa
Paramètre formel a=30
Paramètre effectif age=20

Die Werte der effektiven Parameter „papa“ und 20 wurden in die formalen Parameter S und a kopiert. Diese wurden anschließend geändert. Die effektiven Parameter blieben hingegen unverändert. Dabei ist der Typ der effektiven Parameter zu beachten:

  • S ist eine Objektreferenz auf c.a.d, also die Adresse eines Objekts im Speicher
  • age ist ein ganzzahliger Wert

2.10. Das Beispiel „Steuern“

Wir schließen dieses Kapitel mit einem Beispiel ab, auf das wir im weiteren Verlauf dieses Dokuments noch mehrfach zurückkommen werden. Wir wollen ein Programm schreiben, mit dem sich die Steuer eines Steuerpflichtigen berechnen lässt. Wir betrachten den vereinfachten Fall eines Steuerpflichtigen, der lediglich sein Gehalt anzugeben hat:

  • Wir berechnen die Anzahl der Anteile des Arbeitnehmers nbParts = nbEnfants/2 + 1, wenn er unverheiratet ist, nbEnfants/2 + 2, wenn er verheiratet ist, wobei nbEnfants die Anzahl seiner Kinder ist.
  • Wenn er mindestens drei Kinder hat, erhält er einen halben Anteil zusätzlich
  • sein steuerpflichtiges Einkommen R wird berechnet als R = 0,72 * S, wobei S sein Jahresgehalt ist
  • man berechnet seinen Familienkoeffizienten QF = R / nbParts
  • Man berechnet seine Steuer I. Betrachten wir die folgende Tabelle:
12620,0
0
0
13.190
0,05
631
15640
0,1
1290,5
24.740
0,15
2072,5
31.810
0,2
3309,5
39.970
0,25
4900
48360
0,3
6898,5
55.790
0,35
9316,5
92.970
0,4
12106
127.860
0,45
16.754,5
151250
0,50
23.147,5
172.040
0,55
30.710
195.000
0,60
39312
0
0,65
49062

Jede Zeile enthält 3 Felder. Um die Steuer I zu berechnen, wird die erste Zeile gesucht, in der QF <= Feld 1 gilt. Wenn beispielsweise QF = 23000 ist, wird die Zeile

    24740        0.15        2072.5

Die Steuer I beträgt dann 0,15*R – 2072,5*nbParts. Wenn QF so ist, dass die Beziehung QF <= Feld1 niemals erfüllt ist, werden die Koeffizienten der letzten Zeile verwendet. Hier:

    0                0.65        49062

was die Steuer I = 0,65 * R – 49062 * nbParts ergibt.

Das entsprechende Java-Programm lautet wie folgt:


import java.io.*;

public class impots{

    // ------------ main
    public static void main(String arg[]){

        // Daten

        // Grenzen der Steuerklassen
        double Limites[]={12620, 13190, 15640, 24740, 31810, 39970, 48360,55790, 92970, 127860, 151250, 172040, 195000, 0};    
        // auf die Anzahl der Anteile angewandter Koeffizient
        double Coeffn[]={0, 631, 1290.5, 2072.5, 3309.5, 4900, 6898.5, 9316.5,12106, 16754.5, 23147.5, 30710, 39312, 49062};

        // das Programm

        // Erstellung des Tastatureingabestroms
        BufferedReader IN=null;
        try{
            IN=new BufferedReader(new InputStreamReader(System.in));
        }
        catch(Exception e){
            erreur("Création du flux d'entrée", e, 1);
        }

            // Der Familienstand wird abgerufen
        boolean OK=false;
        String reponse=null;
        while(! OK){
            try{
                System.out.print("Etes-vous marié(e) (O/N) ? ");
                reponse=IN.readLine();
                reponse=reponse.trim().toLowerCase();
                if (! reponse.equals("o") && !reponse.equals("n"))
                    System.out.println("Réponse incorrecte. Recommencez");
                else OK=true;
            } catch(Exception e){
                erreur("Lecture état marital",e,2);
            }
        }
        boolean Marie = reponse.equals("o");

            // Anzahl der Kinder
        OK=false;
        int NbEnfants=0; 
        while(! OK){
            try{
                System.out.print("Nombre d'enfants : ");
                reponse=IN.readLine();
                try{
                    NbEnfants=Integer.parseInt(reponse);
                    if(NbEnfants>=0) OK=true; 
                        else System.err.println("Réponse incorrecte. Recommencez");
                } catch(Exception e){
                    System.err.println("Réponse incorrecte. Recommencez");
                }// try
            } catch(Exception e){
                erreur("Lecture état marital",e,2);
            }// try
        }// while

        // Gehalt
        OK=false;
        long Salaire=0; 
        while(! OK){
            try{
                System.out.print("Salaire annuel : ");
                reponse=IN.readLine();
                try{
                    Salaire=Long.parseLong(reponse);
                    if(Salaire>=0)  OK=true;
                        else System.err.println("Réponse incorrecte. Recommencez");
                } catch(Exception e){
                    System.err.println("Réponse incorrecte. Recommencez");
                }// try
            } catch(Exception e){
                erreur("Lecture Salaire",e,4);
            }// try
        }// while

            // Berechnung der Anzahl der Anteile
        double NbParts;
        if(Marie) NbParts=(double)NbEnfants/2+2;
            else NbParts=(double)NbEnfants/2+1;
        if (NbEnfants>=3) NbParts+=0.5;
        
            // steuerpflichtiges Einkommen
        double Revenu;
        Revenu=0.72*Salaire;

            // Familienquotient
        double QF;
        QF=Revenu/NbParts;
        
            // Ermittlung der Steuerklasse entsprechend QF
        int i;
        int NbTranches=Limites.length;
        Limites[NbTranches-1]=QF;
        i=0;
        while(QF>Limites[i]) i++;
            // die Steuer
        long impots=(long)(i*0.05*Revenu-Coeffn[i]*NbParts);

        // Das Ergebnis wird angezeigt
        System.out.println("Impôt à payer : " + impots);
    }// Hauptbild

    // ------------ Fehler
    private static void erreur(String msg, Exception e, int exitCode){
        System.err.println(msg+"("+e+")");
        System.exit(exitCode);
    }// Fehler

}// Klasse

Die folgenden Ergebnisse wurden erzielt:

C:\Serge\java\impots\1>java impots

Etes-vous marié(e) (O/N) ? o
Nombre d'enfants : 3
Salaire annuel : 200000
Impôt à payer : 16400

C:\Serge\java\impots\1>java impots

Etes-vous marié(e) (O/N) ? n
Nombre d'enfants : 2
Salaire annuel : 200000
Impôt à payer : 33388

C:\Serge\java\impots\1>java impots

Etes-vous marié(e) (O/N) ? w
Réponse incorrecte. Recommencez
Etes-vous marié(e) (O/N) ? q
Réponse incorrecte. Recommencez
Etes-vous marié(e) (O/N) ? o
Nombre d'enfants : q
Réponse incorrecte. Recommencez
Nombre d'enfants : 2
Salaire annuel : q
Réponse incorrecte. Recommencez
Salaire annuel : 1
Impôt à payer : 0