next up previous contents index
Nächste Seite: Ein Streifzug durch Java Aufwärts: Programmieren in Java Vorherige Seite: Programmieren in Java   Inhalt   Index

Unterabschnitte


Objektorientierte Programmierung

Oft genannte Vorteile der OO-Programmierung:

Allerdings:

Daher:



Moderne OO-Sprachen kommen mit

So kann man tatsächlich mit OOP einfach und schnell zu guten Ergebnissen kommen.








Abstraktionen in Programmiersprachen

Die Komplexität der Probleme, die man lösen kann, hängt vom Grad der Abstraktion ab, den die verwendete Programmiersprache bietet:



Imperative Programmiersprachen

Funktionale und logische Programmiersprachen

Man modelliert das zu lösende Problem.

Diese Ansätze sind gut für ihren jeweils typischen Anwendungsbereich. Außerhalb oft unpassend.




Objektorientierte Programmiersprachen

Der Programmierer beschäftigt sich mit Elementen aus der Problemstellung ( Objekten) und ihrer Darstellung im Lösungsraum. Die Anwendbarkeit ist nicht auf einen bestimmten Typ von Problemen beschränkt.




,,Reine`` objektorientierte Sprachen lassen sich wie folgt charakterisieren1:







Schnittstelle und Implementierung

Die Schnittstelle ( interface) eines Objektes legt fest, welche Botschaften ein Objekt verarbeiten kann.



\psfig {figure=bilder/motor.ps}





In Java sieht dies wie folgt aus


    class Motor
    { public void on(){ ... }
      public void off(){ ... }
      public void faster(){ ... }
      public void slower(){ ... }
    }





So erzeugt man einen Motor und macht ihn an:


    Motor mo = new Motor();
    mo.on();






Die Schnittstelle stellt die Charakterisierung eines Objektes für die Öffentlichkeit dar. Versteckt sind (i.d.R.)

Wenn die Schnittstelle sich nicht ändert, kann beides ausgetauscht werden, ohne die Anwendung zu tangieren.





Wiederverwendung

Wiederverwendung und Wiederverwendbarkeit von Klassen ist eines der Schlüssenkonzepte der objektorientierten Programmierung.

Zwei Formen:







Wiederverwendung durch Komposition

Einfachste Art der Wiederverwendung. Eine Klasse wird wiederverwendet, indem Objekte dieser Klasse als Elemente in anderen Klassen benutzt werden.


     class Auto 
     { Motor m;
       Rad r[];
       ...
     }





\psfig {figure=bilder/kompo.ps}






Wiederverwendung durch Vererbung

Vererbung schafft neue Klassen, die von ihrer Elternklasse alle Elemente und die Schnittstelle erben.


     class Diesel extends Motor 
     { ...
     }





Durch die Vererbung der Schnittstelle kann man an die Unterklasse die gleichen Botschaften schicken wie an die Oberklasse. Da der Typ eines Objekts definiert ist durch die Botschaften, die das Objekt versteht, folgt, daß Unter- und Oberklassenobjekte den gleichen Typ haben ( Typäquivalenz).



Einige Sprachen definieren eine ausgezeichnete Klasse, die Oberklasse aller Klassen ist. Diese Klasse ist die Wurzel der Klassenhierarchie.




Eiffel:

GENERAL
Java, Smalltalk:
Object





Vererbung allein bringt noch nichts, da Unter- und Oberklassen nicht nur die gleiche Schnittstelle sondern auch das gleiche Verhalten haben.

Zwei Möglichkeiten:






Je nachdem, ob die erbende Unterklasse nur Methoden überschreibt oder auch Methoden hinzufügt, haben wir zwei Ausprägungen der Beziehung:




\psfig {figure=bilder/vererb.ps}



Polymorphie

Vererbung führt bei einfacher Erbung ( single inheritance) zu baumförmigen Klassenhierarchien.




\psfig {figure=bilder/tree.ps}





Die wichtigste Eigenschaft von Klassenhierarchien:




\psfig {figure=bilder/polymo.ps}




Polymorphie heißt Vielgestaltigkeit:


    Motor m = new Elektro();
    ....
    m = new Diesel();




Polymorphie bedeutet:






Beispiel:




    void motor_check(Motor m)
    { m.on();
      // Motor-Diagnosen
      m.off();
    }
    ...
    Diesel d = new Diesel();
    Elektro e = new Elektro();
    motor_check(d);
    motor_check(e);





Die Formulierung von motor_check() ist typunabhängig:

Nicht

falls Benziner: tue dies;
falls Diesel: tue das;
falls Elektro: tue jenes;

Sondern

Du bist ein Motor. Du weißt selbst,
wie du auf on() reagieren mußt.


m.on() ist der Aufruf der on()-Methode, die für den jeweils gültigen Typ von m zuständig ist (z. B. on() aus Diesel).




Welcher Typ dies ist, steht erst zur Laufzeit des Programmes fest. Der Name on im Aufruf m.on() kann erst dynamisch an eine der verschiedenen on-Ausprägungen gebunden werden.




\psfig {figure=bilder/dynabind.ps}



Lebensraum und Lebensdauer von Objekten

Wo leben Objekte?

Statischer Speicher und Keller:

Heap:






C++, Eiffel:

Freie Auswahl zwischen statischer und dynamischer Allokation
Java, Smalltalk, Delphi
Dynamischer Allokation.
Z.T. automatisches Aufräumen ( Garbage Collection)



Objektzugriff über Referenzen




\psfig {figure=bilder/referenz.ps}

C++


   Motor *mo = new Diesel();
   ...
   mo->on();
Referenzzugriff explizit



Java


   Motor mo = new Diesel();
   ...
   mo.on();
Referenzzugriff implizit
Referenzsemantik gilt für alle Typen (Objekte und Arrays)
außer für die Grundtypen ( int, char, ...).


Objektkopie




Objekte werden bei Referenzsemantik immer über Referenzen manipuliert.




Bei der Zuweisung


    a = b

wird also nur eine Referenz kopiert und kein Wert.




Kopie von Werten erreicht man mit


    Vector b = new Vector();
    c = b.clone();

c verweist auf ein Duplikat von b.



Voraussetzung: Vector implementiert die Methode clone().

Referenzübergabe




Objekte werden bei Referenzsemantik immer über Referenzen manipuliert.




Bei der Parameterübergabe


    swap(a,b);

werden also nur Objektreferenzen übergeben.




Vorsicht: Dies hat nichts mit Call-by-Reference zu tun, wo Adressen von Variablen übergeben werden.




Bei Referenzsemantik der Parameterübergabe funktioniert folgende swap-Funktion NICHT:


    public void swap(Object a, Object b)
    { Object tmp;
      tmp = a;
      a = b;
      b = tmp;
    }

da sie keine Effekte auf ihre aktuellen Parameter ausübt.


Container und Iteratoren

Container:

Objekt, das eine statisch unbestimmte Zahl anderer Objekte aufnehmen kann und dafür eine bestimmte Organisationsform verwendet.

Beispiel:



Schlangen, Bäume, Hash-Tabellen, u.v.a.



Container sind i.a. nicht Element der Sprache sondern Teil von Bibliotheken (C++: STL, Java: API, Delphi VCL)




Iterator:

Ein Iterator für einen Container ist ein Objekt, das dem Anwender den Inhalt des Containers sequentiell präsentiert.

Beispiel:




    Enumeration e = table.elements();
    while (e.hasMoreElements())
        doSomethingWith(e.nextElement());



Generische Typen

Generische Typen erlauben es, Typ-Definitionen mit Typen zu parametrisieren ( Parametrische Polymorphie).

So lassen sich z.B. Container für einen Typ von Inhalt spezialisieren:



C++


    template <class T>
    class Queue 
    { ...
    }
    ...
    Queue<Person> qp;


Java hat keine generischen Typen.



Abhilfe: Container des allgemeinsten Typs Object.


   Motor mo;   // ein Motor
   Queue q;    // eine Schlange von Objects
   q.enq(mo);  // mo in die Schlange

Nachteile:



Um entnommene Objekte verwenden zu können, brauchen wir Typanpassung entgegen der Typhierarchie ( Downcast)!


   mo = (Motor) q.deq();  // raus aus der Schlange

Gefahr:

Vielleicht ist q.deq() gar kein Motor!



Java liefert in diesem Fall eine Laufzeit-Exception. Die notwendige Prüfung kostet Laufzeit.


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