Previous Contents Next

3   Objektorientierte Strukturen (1)

Inhalt Objekte und Klassen ·Vererbung ·Klassenhierarchie ·Überschreiben
Literatur: Die Lektion baut teilweise auf Kapitel 3 aus [Fla99b] auf. Siehe auch Kapitel 4 und 8 aus [LL97]. Eine schöne allgemeine Übersicht und Diskussion über objektorientierte Sprachmerkmale bietet das Buch Object-Oriented Programming [Bud97].
Klassen


Beispiel 4  [Circle]   Der Zustand eines Kreises als einer Instanz von Circle | die Koordinaten seine Zentrums und sein Radius | wird in den entsprechenden Feldern oder Instanzvariablen mit passendem Typ gespeichert.

public class Circle1 {

  //          Felder 
  public double x, y;    // Daten = Koordinaten
  public double r;       // in die Felder

  //          Methoden
  
  public double circumference() {
    return 2 * 3.1415926 * r;
  };                     // 
};                       // '{' und `}' zur Gruppierung


Objekte
Beispiel 5  [Circle]   Zugriff auf den Zustand eines Kreisobjektes = Instanz von Circle1 über seine Felder oder Methoden

Circle1 c = new Circle1();   // Instantiierung

c.x =  4.0;                // Zugriff auf Felder
c.y =  2.3;                // und Methoden mit
c.r = 1.5;                 // `.'

double a = c.circumference();


Selbstreferenz: this


Objekte und Klassen: Konstruktoren
Beispiel 6  [Circle]   Hier das gleiche Beispiel nochmal, diesmal mit (nicht-default) Konstruktor. Instantiierung nun mittels Circle2 c = new Circle2(3.2, 4.5, 1.9).

public class Circle2 {
  private double x, y;    // private: kommt sp"ater 
  private double r;       // genauer
  Circle2 (double _x, double  _y, double _r) {
    x = _x;
    y = _y;
    r = _r;
  };                             // Konstruktor Circle2
  //----------------------------
  public double circumference() {
    return 2 * Math.PI * r;      // Konstante der Klasse Math
  };                   
};


Instanz- und Klassenvariablen


Variablendeklarationen in einer Klasse (Felder) kann man in Instanz- und Klassenvariablen unterteilen

  1. bisher und für gewöhnlich: Instanzvariable: eine Kopie pro Instanz
  2. Klassenvariable oder auch statische Variable:
Beispiel 7  [Anzahl der Instanzen]   Sei ein Kurs durch die Menge seiner Teilnehmer modelliert. Die Klassenvariable freiePlaetze drückt einen globalen ``Zustand'' des Kurses aus.16

public class Teilnehmer {
  public static int freiePlaetze = 10;   
  public String name;
  public int matrikelnummer;
  
  Teilnehmer(String n, int m) {
    name  = n;
    matrikelnummer = m;  
    freiePlaetze--;       // einer weniger frei
  };                      // Konstruktor
};


Klassenmethoden, statische Methoden


Analog der Situation bei Feldern unterscheidet man Instanz- und Klassenmethoden.
  1. bisher (fast) nur Instanzmethoden
  2. Klassenmethoden oder auch statische Methoden
Initialisierung von Klassenvariablen
Lebensende von Objekten: Müllabfuhr und Finalisierung


Unterklassen und Vererbung


Beispiel 8  [Konto]  

public class Konto {
  int    kontostand;
  String inhaber;
  Konto (String name, int i) {       
    kontostand = i;
    inhaber = name;
  };
  Konto (String name) {  // konstruktor-overloading
    kontostand = 0;
    inhaber    =  name;
  };
  /*  Konto (){
    kontostand = 0;
    inhaber    =  "";
  };
  */
  //-----------------------------------------
  public void einzahlen (int betrag) {
    kontostand += betrag;
  };
  public void auszahlen (int betrag) {
    kontostand -= betrag;
  }

  public int wieviel  () {
    return kontostand;
  };
};
    


Beispiel 9  [Sparkonto]   Ein Sparkonto sei eine besondere Art von Konto, die auch noch Verzinsung bietet.

public class Sparkonto extends Konto { // Unterklasse
  double  z_faktor;
  double  ueberziehungsz_faktor;
  Sparkonto (double z_satz, double z_satz2, String name, int i) {
    super(name,i);
    z_faktor               = 1+ z_satz /100;
    ueberziehungsz_faktor  = 1+ z_satz2/100;
  };
  Sparkonto (double z_satz, String name) {
    super(name);                     // this.inhaber = name; 
                                     // w"are falsch
    z_faktor             = 1 + z_satz/100;
  };
  /* Sparkonto(double rate) {... ginge nicht, denn
     super hat kein Konto()-Konstruktor */
  // ------------------------------------------------
  public void verzinsen() {
    kontostand = (int) (z_faktor * kontostand);
  };

  public void auszahlen (int betrag) {   // "Uberschreiben
    if (kontostand >= betrag)
      kontostand -= betrag;
  };
};


Klassenhierarchie


Überschreiben von Methoden


Beispiel 10  [Überschreiben]   Hier ein Beispiel, welches Vererbung mit Überschreibung von Feldern und Methoden auf etwas merkwürdige Weise kombiniert.



class A {
  int i = 1;
  int f() { return i;}
};

public class B extends A {
    int i;
    int f() {
 System.out.println("i = " + i);
 i = super.i + 1;
 System.out.println("i = " + i);
 System.out.println("super.f() = " + super.f());
 return super.f() + i;
    };
};




public class Main {
  public static void main (String[] args) {
    B b = new B();
    System.out.println("i = " + b.f());
  };
}



Die Ausgabe Beim Ausführen von main ist (bis auf die ``newlines''):i=5; i=2; super.f() = 1; i = 3.22 Das erste i ist klar, es ist einfach die in B vorhanden Version von i die die aus A überschreibt (genauer gesagt überschattet (shadowed)). Die Zuweisung danach setzt i dann auf 2, wegen super, der Wert von i in A ändert sich damit nicht. Das Ergebnis des Aufrufes von super.f ist interessant, es greift auf die Variable von A zu und liefert das, wie gesagt, unveränderte i = 1. Der Returnwert 3 am Ende sollte damit klar sein.

Wenn wir das Beispiel
ändern indem wir die Zeile int i = 5; aus B entfernen, erhalten wir folgendes Ergebnis: i = 1; i = 2; super.f() = 2; i = 4. Das erste i ist klar: da B das Feld i nicht einführt, erbt es das aus A mit dem Wert 1. Auch die nächste Ausgabe ist klar: 1+1 = 2. Interessant die Ausgabe von super.f, diesmal ergibt es den Wert 2, da wir diesmal nur eine Kopie des Feldes in A und B haben. Die Rückgabe von 4 ist dann klar.

Statisch vs. Dynamisch


Beispiel 11  

class A {
  public int x = 3;
  public void test  () { System.out.println("A"); }
  public void test2 () { System.out.println("x = " +  x); }
};

class B extends A {
  public int x = 4;
  public void test () {  System.out.println("B"); }
  public void test2 () { System.out.println("x = " + x); }
};

public class Main2 {
    public static void main (String[] args) {
        A a = new A();
        A b; b = new B();  // die wichtige Zeile!
        b.test();
        b.test2();
        System.out.println("b.x = " + b.x);
    }
}



Dieses Beispiel zeigt klar den Unterschied zwischen statischer und dynamischer Bindung und auch den Unterschied zwischen Deklaration einer Referenzvariablen und dem Instanziierung den Objekts: Felder sind statisch gebunden und Methoden dynamisch.23

Die Ausgabe des Programms lautet B; x = 4; b.x = 3. Der Aufruf der Methode test an b liefert die Methode in B, das selbe für den Aufruf von test2. Das interessante (oder krumme) ist der Unterschied zu b.x der dadurch kommt, daß b als vom Typ/Klasse A deklariert ist! Schriebe man B b anstelle dessen, wäre die Ausgabe von b.x ebenfalls 4!24

Kapselung

erlaubter Zugriff Sichtbarkeit
  public protected default private
selbe Klasse Ja Ja Ja Ja
selbes Paket Ja Ja Ja Nein
Unterklassen (anderes Paket) Ja Ja Nein Nein
beliebige Klasse Ja Nein Nein Nein

Table 2: Sichtbarkeitsmodifikatoren


Kapselung (2)


Ein paar Daumenregeln für die verschiedenen Sichtbarkeitsstufen
Abstrakte Klassen

17. April 2000


July 4, 2000
Previous Contents Next