© APSIS GmbH extern.gif (1249 Byte), Polling, 2000, 2001, 2002, 2003


Ergänzungen

zur 3. Auflage

Stand: 6. Juni 2001


Seite 61, vorletzter Absatz:

Nach dem letzten Satz des Absatzes (d.h. vor dem letzten Absatz) kann eingefügt werden:

Die Spezifizierung ungeprüfter Ausnahmen ist nur ein Kommentar, zumal der Compiler ihre Behandlung nicht überprüft.


Seite 105, nach dem ersten Programmstück kann der Absatz eingefügt werden:

Das reservierte Wort final im Profil einer Methode bewirkt, dass sie nicht überschrieben werden kann.


Seite 129, nach der Abbildung 5.10 kann der Absatz eingefügt werden:

An diesem Beispiel ist die Behälterhierarchie wahrnehmbar: das dem JApplet zugeordnete Container-Objekt (erhalten durch getContentPane) enthält das JComboBox-Objekt (referiert durch auswahl), weil es ihm in der letzten Programmzeile (mit add) hinzugefügt wurde. Das JComboBox-Objekt enthält seinerseits die drei String-Objekte, die mit addItem hinzugefügt wurde. Im Kapitel 6.5.8. auf Seite 164 werden wir eine noch komplexere Behälterhierarchie untersuchen.


Seite 141, nach dem Programm 6.9 (unten auf der Seite) kann der Absatz eingefügt werden:

Wenn die geschachtelte Klasse in einer static-Methode ausgeprägt wird, muss sie selber als static gekennzeichnet werden:

import lehrbuch.Eimer;
public class StatischeKlassen extends java.applet.Applet {
è       private static class ErsetzenMenue extends lehrbuch.kapitel6.FreiMenue {
      ... // wie im Programm (6.8)
   }
   public static void main(String[] kzp) { ... // wie im Programm (6.8)
è          new ErsetzenMenue().menue(links, rechts);
   }
}

Seite 164

Als letzter Abschnitt des Kapitels 6 kann der Abschnitt eingefügt werden:

6.6. Die Behälterhierarchie

Im Kapitel Kapitel 5.7. auf Seite 125 haben wir schon die Behälterhierarchie  erwähnt: Behälterobjekte (Objekte der Klasse Container) können andere Behälterobjekte enthalten, die ihrerseits weitere Objekte enthalten. Sie werden einander mit add- oder set-Methoden hinzugefügt. Nach der Namenskonvention der Standardklassen kann eine add-Methode (wie add, add­Action­Listener, addItem, usw.) einem Behälter mehrere Objekte hinzufügen, während die set-Methoden (setMenuBar, setText, usw.) jeweils nur ein Objekt hinzufügen. Ein weiterer Aufruf einer set-Methode überschreibt typischerweise die alte Eintragung. Zu den add-Methoden finden wir häufig entsprechende remove-Methoden (z.B. removeActionListener), mit denen einzelne hinzugefügte Objekte entfernt werden können. So können beispielsweise bei einem Knopf mehrere Lauscher registriert werden, die beim Drücken des Knopfs in der Reihenfolge der Eintragung abgearbeitet (d.h. ihre action­Per­for­med-Methoden aufgerufen) werden. Diese können dynamisch hinzugefügt und entfernt (und so die Funktionalität des Knopfes zur Laufzeit) verändert werden.

Einem Frame-Objekt kann jedoch nur eine Menüleiste (mit setMenuBar) zugeordnet werden. Da ein weiterer Aufruf von setMenuBar die alte Menüleiste entfernt, können zur Laufzeit die Menüleisten gewechselt werden.

Der Mechanismus, wie Objekte einem Container-Objekt hinzugefügt werden, ist einfach: Die add- und set-Methoden tun nichts anderes, als im Container-Objekt eine hierfür vorgesehene Referenz auf das Parameterobjekt setzen. Hierbei seht für set-Methoden nur eine Referenz zur Verfügung (die überschrieben werden kann), für add-Methoden eine ganze Liste von Referenzen, die beliebig verlängert werden kann.

Beispielsweise kann die Behälterhierarchie des Programms (6.28) auf Seite 162 folgenderweise dargestellt werden:

Abb. 6. 15 : Behälterhierarchie

Im Programm (6.29) auf Seite 162 werden noch zusätzlich drei JButton-Objekte und ein JLabel-Objekt dem Container-Objekt (referiert durch flaeche) hinzugefügt; dieses letztere hängt in einer Referenz im JFrame-Objekt. Die drei JButton- und die drei JMenuItem-Objekte enthalten hier noch eine Referenz, in der Lauscher eingehängt sind; diese Rolle spielt hier das JFrame-Objekt, das selbst gleich ein Action­Lis­te­ner-Objekt ist.

Diese Darstellung ist jedoch etwas vereinfacht; in der Wirklichkeit spielen noch eine ganze Reihe anderer Klassen und Objekte eine Rolle.

Hier wird jedoch noch eine Tatsache wahrnehmbar: Die Oberflächenobjekte werden in einem Block (im Rumpf der Methode init oder im Konstruktor) erzeugt und in lokale Referenzen eingehängt. Nach der Beendigung des Blocks werden diese Referenzen vom Stapel gelöscht. Die von ihnen Objekte werden jedoch von der automatischen Speicherbereinigung nicht entsorgt, weil sie weiter über die oben dargestellte Verkettung erreichbar sind.


Seite 178

Nach dem Programm 7.11 kann der Absatz eingefügt werden:

Der Wertebereich von float reicht ungefähr von 1.5 × 10−45 bis 3.4 × 1038 mit einer Genauigkeit von 7 Dezimalstellen. Der Wertebereich von double reicht ungefähr von 5.0 × 10−324 bis 1.7 × 10308 mit einer Genauigkeit von 15-16 Dezimalstellen.

C# kennt außerdem folgende besondere Bruchwerte (entsprechend des Industriestandards IEEE 754):

· Positive und negative 0 (meistens gleich behandelt)

· Positive und negative „unendlich“ (Ergebnis der Division 1 und –1 durch 0)

· Der Wert NaN – not a Number, „keine Zahl“ ((Ergebnis der Division 0 durch 0)


Seite 181

Nach den ersten 3 Zeilen kann der Absatz eingefügt werden:

Eine statische Methode mit zwei (Lese-)Parametern

Klasse.Methode(links, rechts)

kann ebenfalls als Operator

links operator rechts

formuliert werden.


Seite 196

Nach dem ersten Programmabschnitt kann der Text eingefügt werden:

Die Operatoren haben neben Priorität auch eine Assoziativität : Damit wird ausgedrückt, in welcher Richtung Operatoren gleicher Prioriät in einem Ausdruck ohne Klammerung ausgewertet werden. Die Zuweisungsoperatoren und der (triadische) Bedingungsoperator sind rechtsassoziativ , die anderen diadischen Operatoren sind linksassoziativ :

a = b = c ist gleichwertig mit a = (b = c) (linksassoziativ)
a + b + c ist gleichwertig mit (a + b) + c (rechtsassoziativ)

Die (monadischen) Präfix-Operatoren sind rechtsassoziativ, die Postfix-Operatoren sind linksassoziativ:

! ! a ist gleichwertig mit ! (! a) (rechtsassoziativ)
a ++ -- ist gleichwertig mit (a ++) -- (linksassoziativ)
Die Prioriäteten und Assoziativität der Operatoren macht zwar für den Compiler jeden Ausdruck eindeutig, nicht aber für den menschlichen Leser.

Seite 297

Als letzter Abschnitt des Kapitels 10 kann der Abschnitt eingefügt werden:

10.7. Gruppierung von Multibehältern

Multibehälter können nach verschiedenen Gesichtspunkten gruppiert werden:

1. Verhalten

2. Elementtyp

3. Bestimmung der Größe

Der Unterschied nach Verhalten liegt hauptsächlich beim Zugriff (Lesen/Entfernen) auf die eingetragenen Elemente:

1.1. Wahlfreier Zugriff (Menge, Sack, Assoziativspeicher, Direkte Datei)

1.2. Gebundener Zugriff (Stapel, Warteschlange, sequentielle Datei, Sortierkanal)

Der Unterschied nach Elementtyp liegt darin, welche Arten von Daten gespeichert werden können:

2.1. Fest (im Programmcode) vorgegeben:

2.1.1. Basistyp (int, usw.)

2.1.2. Objekte (z.B. Farbmenge)

2.2. Beliebige Objekte (polymorphe Multibehälter)

2.3. Bei der Ausprägung (durch Registrierungsobjekt) wählbarer Typ (generische Multibehälter)

2.4. Unterklassen einer fest vorgegebenen Klasse (z.B. Aufz bei diskreten Multibehältern)

Die Bestimmung der Größe kann zu unterschiedlichen Zeitpunkten stattfinden:

3.1. Fest (im Programmcode) vorgegeben (z.B. 3 bei Farbmenge, 20 bei Stapel)

3.2. Bei der Ausprägung als Konstruktorparameter anzugeben (Reihungsimplementierungen)

3.3. Dehnbar (z.B. Vector)

3.4. Flexibel (Listenimplementierungen)


Seite 306

Als letzter Abschnitt des Kapitels 11.2 kann der Abschnitt eingefügt werden:

11.2.5. Animation

Animationen können mit Hilfe von nebenläufigen Prozessen durchgeführt werden. Typischerweise wird ein Prozess (im untenstehenden Programm Animator) gestartet, dessen einzige Aufgabe ist, in regelmäßigen Abständen repaint für ein JFrame-Objekt aufzurufen. Dadurch wird die paint-Methode jeweils aufgerufen. Bei jedem Aufruf zeichnet sie das nächste Bild:

import java.awt.*; import java.awt.event.*; import javax.swing.*;     // (11.8)
class Animator extends Thread {
   private Frame rahmen;
   public Animator(Frame rahmen) { this.rahmen = rahmen; }
   public void run() {
      while(true) {
è              rahmen.repaint();
          try {
             Thread.sleep(50);
          } catch (InterruptedException e) { } } } }
public class EimerAnimation extends JFrame {
   public EimerAnimation() {
      super("EimerAnimation"); anim = new Eimeranim(true, true, 2); // Wasser füllen
      setBackground(Color.lightGray);
      addWindowListener(new WindowAdapter() {
          public void windowClosing(WindowEvent event) { System.exit(0); } });
      super.setSize(600, 600); 
      bildbreite = getSize().width; bildhoehe = getSize().height;
      super.setVisible(true); 
      new Animator(this).start(); }
   public static void main(String[] args) { new EimerAnimation(); }
   private Eimeranim anim;
è       public void paint(Graphics grafik) { 
      anim.animieren(grafik, getHeight(), getWidth()); } }
class Eimeranim {
   public Eimeranim(boolean inhalt, boolean richtung, int pos) {
      i = richtung ? 1 : ANZAHL;
      fertig = false; this.inhalt = inhalt; this.pos = pos; this.richtung = richtung; }
   private int pos, i; // Laufvariable
   private boolean fertig, inhalt, richtung;
   void animieren(Graphics grafik, int imax, int jmax) {
      grafik.clearRect(linkerLinksX, linkerObenY, 3 * DIAM, HOEHE + DIAM);
      grafik.setColor(Color.black);
      grafik.drawLine(rumpfLinksX, rumpfObenY, rumpfLinksX, rumpfUntenY); // linke Seite
      grafik.drawLine(rumpfRechtsX, rumpfObenY, rumpfRechtsX, rumpfUntenY); // rechte
      grafik.drawArc(linkerLinksX, linkerObenY, DIAM, DIAM,linkerAnfang,linkerBogen);
      grafik.drawArc(rechterLinksX, rechterObenY, DIAM, DIAM,
          rechterAnfang, rechterBogen);
      grafik.drawArc(untererLinksX, untererObenY, DIAM, DIAM,
          untererAnfang, untererBogen);   
      if (i > 0) { // der Eimerinhalt wird gemalt:
          grafik.setColor(inhalt ? Color.blue : Color.red);
          grafik.fillArc(untererLinksX+1, untererObenY, DIAM-1, DIAM,
             untererAnfang, untererBogen);
             grafik.fillRect(rumpfLinksX+1, Y + HOEHE - i * SCHRITT, DIAM-1, i*SCHRITT);
          if (richtung && i < ANZAHL) // von unten nach oben füllen
             i++;
          else if (! richtung && i > 0)// von oben nach unten füllen (d.h. entleeren)
             i--; } } }

Im obigen Programm wird die Klasse Eimeranim zu Testzwecken ausgeprägt. Sie ist in der Lage, einen einfachen Eimer mit dem angegebenen inhalt (true ist Color.blau) in die angegebene richtung (true ist von unten nach oben, d.h. füllen) und an der angegeben Position pos (0 ist links oben) zu animieren. Die Konstanten für die Geometrie des Eimers (wie DIAM, rumpfLinksX, usw.) haben wir im obigen Programm weggelassen.


Fehler, Korrekturen und Verbesserungsvorschläge können auf die folgende Adresse zugeschickt werden:


© APSIS GmbH extern.gif (1249 Byte), Polling, 2000, 2001, 2002, 2003