Objekt: Unterschied zwischen den Versionen
Marius (Diskussion | Beiträge) (Die Seite wurde neu angelegt: „=Konzept= Das Konzept der objektorientierten Software ist es, Software so zu organisieren, dass sie dem Denkstil des objektorientierten menschlichen Gehirns e…“) |
|||
(15 dazwischenliegende Versionen von 3 Benutzern werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
+ | Ein '''Objekt''' ist eine thematische Zusammenfassung von Daten. Auf Datenebene entspricht ein Objekt nur einem zusammenhängenden Speicherblock. Anstatt jedoch die Bedeutung des Inhaltes dieses Speicherbereiches manuell zu interpretieren, bieten [[Objektorientierte Programmierung|objektorientierte Programmiersprachen]] dem Programmierer die Möglichkeit, diese Daten direkt mit einer '''Semantik''' zu versehen. | ||
+ | |||
+ | Der Aufbau eines Objektes wird durch seine [[Klasse]] bestimmt: | ||
+ | |||
+ | * Die [[Attribut | Attributvariablen]] repräsentieren die gespeicherten '''Daten'''. | ||
+ | * Die [[Methode | Methoden]] repräsentieren die auf diesen Daten ausführbaren '''Operationen'''. | ||
+ | * Die [[Konstruktor | Konstruktoren]] repräsentieren die '''Art und Weise''', in der der Speicherbereich initialisiert wird. | ||
+ | |||
=Konzept= | =Konzept= | ||
− | Das Konzept der objektorientierten Software ist es, Software so zu organisieren, dass sie dem Denkstil des | + | ==Erläuterung== |
+ | |||
+ | Das Konzept der '''objektorientierten Software''' ist es, Software so zu organisieren, dass sie dem objektorientierten Denkstil des menschlichen Gehirns entspricht. Für einen Menschen ist die Idee eines handlungsfähigen Objektes greifbarer, als die einer Ansammlung abstrakter Daten irgendwo im Speicher des Computers. | ||
+ | |||
+ | == Beispiel == | ||
+ | |||
+ | Ein '''Quader''' kann durch folgende Werte repräsentiert werden: Höhe, Breite und Tiefe. Diese drei Werte können in Form dreier [[Double|<code>double</code>-Variablen]] vermerkt werden. Im Speicher kann ein Quader also durch drei <code>double</code>-Variablen direkt hintereinander repräsentiert werden und verbraucht dabei 192 Bit an Platz. Zwei Quader, ein länglicher Block und ein Würfel, ließen sich dann folgendermaßen verwalten: | ||
+ | |||
+ | <source lang="java"> | ||
+ | double blockWidth = 2.0; | ||
+ | double blockHeight = 3.0; | ||
+ | double blockLength = 6.0; | ||
+ | |||
+ | double cubeWidth = 4.0; | ||
+ | double cubeHeight = 4.0; | ||
+ | double cubeLength = 4.0; | ||
+ | </source> | ||
+ | |||
+ | ===Problematik=== | ||
+ | |||
+ | Für zwei solcher Datensätze mag das noch ganz übersichtlich erscheinen. Sobald man aber Hunderte Objekte dieser Art verwalten will, wie z.B. in der Computergrafik üblich, so geht sehr schnell die Übersicht verloren. Ein weiteres Problem ist, dass diese Daten nicht verallgemeinert verwaltbar sind. Es ist nicht möglich, ''irgendeinen'' dieser Quader zu wählen und mit seinen Daten zu arbeiten. Stattdessen muss jeder Quader direkt bearbeitet und seine Daten verwaltet werden. So sind z.B. leicht geschriebene [[Schleifen]] über ''alle'' Quader nicht umsetzbar. | ||
+ | |||
+ | ===Lösung=== | ||
+ | Man definiert sich für seine Quader einen eigenen [[Datentyp|'''Datentyp''']]: | ||
+ | |||
+ | <source lang="java" title="Quaderklasse mit Attributen"> | ||
+ | public class Cuboid { | ||
+ | private double width; | ||
+ | private double height; | ||
+ | private double length; | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | Durch diese Klasse werden bereits alle benötigten Daten zum Repräsentieren eines Quaders reserviert. | ||
+ | |||
+ | ====Konstruktoren==== | ||
+ | |||
+ | Mit dem [[Konstruktor#Default-Konstruktor|Defaultkonstruktor]] kann man bereits Quader erzeugen: | ||
+ | |||
+ | <source lang="java" title="Quader mit Defaultkonstruktor instanziieren"> | ||
+ | Cuboid[] cuboids = new Cuboid[10]; | ||
+ | for(int i = 0; i < 10 ; i++){ | ||
+ | cuboids[i] = new Cuboid(); | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | Man kann jedoch die Daten dieser Quader selbst noch nicht verändern. Dazu schreibt man für gewöhnlich [[Konstruktor | Konstruktoren]], die die Daten initialisieren: | ||
+ | |||
+ | <source lang="java" title="Quaderklasse mit Konstruktor"> | ||
+ | public class Cuboid { | ||
+ | private double width; | ||
+ | private double height; | ||
+ | private double length; | ||
+ | |||
+ | public Cuboid(double width, double height, double length){ | ||
+ | this.width = width; | ||
+ | this.height = height; | ||
+ | this.length = length; | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | Den Defaultkonstruktor kann man nun nicht mehr verwenden, man muss einen '''öffentlichen Konstruktor''' aufrufen: | ||
+ | |||
+ | <source lang="java" title="Quader mit eigenem Konstruktor instanziieren"> | ||
+ | Cuboid[] cuboids = new Cuboid[10]; | ||
+ | for(int i = 0; i < 10 ; i++){ | ||
+ | cuboids[i] = new Cuboid(i+1,i+2,i+3); | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | Jedes der so erstellten Objekte besitzt nun individuelle Werte und kann über das [[Array]] angesprochen werden. | ||
+ | Die sechs Zeilen Code des ersten Beispieles lassen sich jetzt auch folgendermaßen darstellen: | ||
+ | |||
+ | <source lang="java"> | ||
+ | Cuboid block = new Cuboid(2.0,3.0,6.0); | ||
+ | Cuboid cube = new Cuboid(3.0,3.0,3.0); | ||
+ | </source> | ||
+ | |||
+ | ====Methoden==== | ||
+ | |||
+ | Möchte man mit diesen Objekten arbeiten, so kann man '''relevante Operationen''' auch als Methoden des Objektes formulieren. Eine relevante Operation wäre hier zum Beispiel die Berechnung des Volumens der Quader: | ||
+ | |||
+ | <source lang="java" title="Quaderklasse mit Volumenberechnungsmethode"> | ||
+ | public class Cuboid { | ||
+ | private double width; | ||
+ | private double height; | ||
+ | private double length; | ||
+ | |||
+ | public Cuboid(double width, double height, double length){ | ||
+ | this.width = width; | ||
+ | this.height = height; | ||
+ | this.length = length; | ||
+ | } | ||
+ | |||
+ | public double getVolume(){ | ||
+ | return this.width * this.height * this.length; | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | Mit Verwendung sieht das ganze folgendermaßen aus: | ||
+ | |||
+ | <source lang="java" title="Ausgabe der Volumina"> | ||
+ | Cuboid[] cuboids = new Cuboid[10]; | ||
+ | for(int i = 0; i < 10 ; i++){ | ||
+ | cuboids[i] = new Cuboid(i+1,i+2,i+3); | ||
+ | } | ||
+ | [...] | ||
+ | for(int i = 0; i < 10; i++){ | ||
+ | System.out.println("Volume of Cuboid #"+i+": "+cuboids[i].getVolume()); | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | =Eigenschaften eines Objektes= | ||
+ | |||
+ | == Zustand == | ||
+ | |||
+ | ===Erläuterung=== | ||
+ | |||
+ | Jedes Objekt ist eine einzelne Instanz einer [[Klasse]]. Jedes Objekt einer Klasse besitzt seine eigenen, persönlichen '''Attribute'''. Deren direkte Manipulation hat keinen Einfluss auf die Attribute anderer Objekte dieser Klasse. | ||
+ | |||
+ | Die individuellen Werte der Attribute eines Objektes nennt man daher auch seinen '''Zustand'''. | ||
+ | |||
+ | Zur Änderung eines Zustandes kann man '''[[Setter]]''' programmieren. Setter ändern das Attribut des Objektes, auf dem sie aufgerufen werden. Natürlich dürfen auch andere Methoden den Zustand eines Objektes ändern, dies sollte allerdings vom Programmierer dokumentiert werden. | ||
+ | |||
+ | === Beispiel === | ||
+ | |||
+ | <source lang="java" title="Setter eines Quaders"> | ||
+ | [...] | ||
+ | public void setWidth(double width){ | ||
+ | this.width = width; | ||
+ | } | ||
+ | [...] | ||
+ | </source> | ||
+ | |||
+ | Hier ändert ein Setter die Breite des Quaders. | ||
+ | |||
+ | == Verhalten == | ||
+ | Die innerhalb der Klasse definierten (nicht statischen) Methoden können nur ''auf'' einem Objekt ausgeführt werden. Anders formuliert: Das Objekt führt die Methode aus. Das Verhalten der Methode ist abhängig vom Zustand des Objektes, das die Methode ausführt. So gibt z.B. die oben erwähnte <code>getVolume()</code>-Methode für jedes Objekt einen anderen Wert zurück. Das Ergebnis ist also '''abhängig vom Zustand''' (den Attributen) des Objektes. | ||
+ | |||
+ | = Lebenszyklus = | ||
+ | |||
+ | Ein Objekt repräsentiert Daten. Diese liegen im Speicher des Rechners. Wird ein Objekt erzeugt, so verbraucht es den Speicher des Rechners, indem entsprechend der Größe des Objektes Speicher für dieses reserviert wird. Wird ein Objekt nicht mehr benötigt, so wird der von ihm reservierte Speicher wieder freigegeben. | ||
+ | |||
+ | == Instanziierung == | ||
+ | siehe auch: [[Instanziierung]] | ||
+ | |||
+ | Ein Objekt wird erzeugt, oder instanziiert, indem sein [[Konstruktor]] mit dem [[Schlüsselwörter|Schlüsselwort]] '''new''' aufgerufen wird: <code>new Object();</code> . | ||
+ | Damit existiert ein Objekt immer erst zur [[Laufzeit]] des Programms. | ||
+ | == Freigabe == | ||
+ | Ein Objekt verbleibt so lange im Speicher des Rechners, wie das ausführende Programm noch eine Referenz auf das Objekt verwaltet. Das heißt, ein Objekt wird nur dann gelöscht, wenn es nicht mehr verwendet werden ''kann''. Ein System der [[Java Virtual Machine|JVM]], der [[Garbage Collector]], gibt den Speicher dieses Objektes dann wieder frei. | ||
− | = | + | == Beispiele == |
− | + | 1. Wird nur der Konstruktor eines Objektes aufgerufen, ohne das neue Objekt einer Variablen zuzuweisen, so wird es beim nächsten Durchlauf des [[Garbage Collector | Garbage Collectors]] wieder freigegeben: | |
− | + | ||
+ | <source lang="java"> | ||
+ | new Cuboid(3.0,3.0,3.0); | ||
+ | </source> | ||
− | + | 2. Wird ein Objekt lokal in einer Methode in einer Variablen vermerkt und seine Referenz ansonsten nicht weiter nach Außen gegeben, so wird das Objekt nach Verlassen der Methode freigegeben: | |
− | + | ||
+ | <source lang="java"> | ||
+ | [...] | ||
+ | public void printVolume(double w, double h, double l){ | ||
+ | Cuboid block = new Cuboid(w,h,l); | ||
+ | System.out.println(block.getVolume()); | ||
+ | } | ||
+ | [...] | ||
+ | </source> | ||
− | + | 3. Ist ein Objekt Teil eines anderen Objektes, z.B. als Attribut, so existiert das Objekt genau so lange, wie das ihn beinhaltende Objekt existiert (solange seine Referenz weiterhin nicht an einen anderen erreichbaren Teil des Programms übergeben wurde): | |
− | + | ||
+ | <source lang="java"> | ||
+ | public class CubeContainer { | ||
+ | private Cuboid cube; | ||
+ | public CubeContainer(double edge){ | ||
+ | this.cube = new Cube(edge, edge, edge); | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | 4. Wird ein Objekt als Parameter einer Methode erwartet und beim Aufruf dieser Methode instanziiert, so existiert seine Referenz innerhalb der aufgerufenen Methode. Wird die Referenz danach weiterhin nicht nach Außen gereicht, wird das Objekt nach dem Verlassen der Methode freigegeben. | ||
− | = | + | <source lang="java"> |
− | + | [...] | |
+ | public void printCube(double edge){ | ||
+ | System.out.println(new Cube(edge, edge, edge)); | ||
+ | } | ||
+ | [...] | ||
+ | </source> |
Aktuelle Version vom 26. Juli 2016, 11:58 Uhr
Ein Objekt ist eine thematische Zusammenfassung von Daten. Auf Datenebene entspricht ein Objekt nur einem zusammenhängenden Speicherblock. Anstatt jedoch die Bedeutung des Inhaltes dieses Speicherbereiches manuell zu interpretieren, bieten objektorientierte Programmiersprachen dem Programmierer die Möglichkeit, diese Daten direkt mit einer Semantik zu versehen.
Der Aufbau eines Objektes wird durch seine Klasse bestimmt:
- Die Attributvariablen repräsentieren die gespeicherten Daten.
- Die Methoden repräsentieren die auf diesen Daten ausführbaren Operationen.
- Die Konstruktoren repräsentieren die Art und Weise, in der der Speicherbereich initialisiert wird.
Inhaltsverzeichnis
Konzept
Erläuterung
Das Konzept der objektorientierten Software ist es, Software so zu organisieren, dass sie dem objektorientierten Denkstil des menschlichen Gehirns entspricht. Für einen Menschen ist die Idee eines handlungsfähigen Objektes greifbarer, als die einer Ansammlung abstrakter Daten irgendwo im Speicher des Computers.
Beispiel
Ein Quader kann durch folgende Werte repräsentiert werden: Höhe, Breite und Tiefe. Diese drei Werte können in Form dreier double
-Variablen vermerkt werden. Im Speicher kann ein Quader also durch drei double
-Variablen direkt hintereinander repräsentiert werden und verbraucht dabei 192 Bit an Platz. Zwei Quader, ein länglicher Block und ein Würfel, ließen sich dann folgendermaßen verwalten:
double blockWidth = 2.0; double blockHeight = 3.0; double blockLength = 6.0; double cubeWidth = 4.0; double cubeHeight = 4.0; double cubeLength = 4.0;
Problematik
Für zwei solcher Datensätze mag das noch ganz übersichtlich erscheinen. Sobald man aber Hunderte Objekte dieser Art verwalten will, wie z.B. in der Computergrafik üblich, so geht sehr schnell die Übersicht verloren. Ein weiteres Problem ist, dass diese Daten nicht verallgemeinert verwaltbar sind. Es ist nicht möglich, irgendeinen dieser Quader zu wählen und mit seinen Daten zu arbeiten. Stattdessen muss jeder Quader direkt bearbeitet und seine Daten verwaltet werden. So sind z.B. leicht geschriebene Schleifen über alle Quader nicht umsetzbar.
Lösung
Man definiert sich für seine Quader einen eigenen Datentyp:
public class Cuboid { private double width; private double height; private double length; }
Durch diese Klasse werden bereits alle benötigten Daten zum Repräsentieren eines Quaders reserviert.
Konstruktoren
Mit dem Defaultkonstruktor kann man bereits Quader erzeugen:
Cuboid[] cuboids = new Cuboid[10]; for(int i = 0; i < 10 ; i++){ cuboids[i] = new Cuboid(); }
Man kann jedoch die Daten dieser Quader selbst noch nicht verändern. Dazu schreibt man für gewöhnlich Konstruktoren, die die Daten initialisieren:
public class Cuboid { private double width; private double height; private double length; public Cuboid(double width, double height, double length){ this.width = width; this.height = height; this.length = length; } }
Den Defaultkonstruktor kann man nun nicht mehr verwenden, man muss einen öffentlichen Konstruktor aufrufen:
Cuboid[] cuboids = new Cuboid[10]; for(int i = 0; i < 10 ; i++){ cuboids[i] = new Cuboid(i+1,i+2,i+3); }
Jedes der so erstellten Objekte besitzt nun individuelle Werte und kann über das Array angesprochen werden. Die sechs Zeilen Code des ersten Beispieles lassen sich jetzt auch folgendermaßen darstellen:
Cuboid block = new Cuboid(2.0,3.0,6.0); Cuboid cube = new Cuboid(3.0,3.0,3.0);
Methoden
Möchte man mit diesen Objekten arbeiten, so kann man relevante Operationen auch als Methoden des Objektes formulieren. Eine relevante Operation wäre hier zum Beispiel die Berechnung des Volumens der Quader:
public class Cuboid { private double width; private double height; private double length; public Cuboid(double width, double height, double length){ this.width = width; this.height = height; this.length = length; } public double getVolume(){ return this.width * this.height * this.length; } }
Mit Verwendung sieht das ganze folgendermaßen aus:
Cuboid[] cuboids = new Cuboid[10]; for(int i = 0; i < 10 ; i++){ cuboids[i] = new Cuboid(i+1,i+2,i+3); } [...] for(int i = 0; i < 10; i++){ System.out.println("Volume of Cuboid #"+i+": "+cuboids[i].getVolume()); }
Eigenschaften eines Objektes
Zustand
Erläuterung
Jedes Objekt ist eine einzelne Instanz einer Klasse. Jedes Objekt einer Klasse besitzt seine eigenen, persönlichen Attribute. Deren direkte Manipulation hat keinen Einfluss auf die Attribute anderer Objekte dieser Klasse.
Die individuellen Werte der Attribute eines Objektes nennt man daher auch seinen Zustand.
Zur Änderung eines Zustandes kann man Setter programmieren. Setter ändern das Attribut des Objektes, auf dem sie aufgerufen werden. Natürlich dürfen auch andere Methoden den Zustand eines Objektes ändern, dies sollte allerdings vom Programmierer dokumentiert werden.
Beispiel
[...] public void setWidth(double width){ this.width = width; } [...]
Hier ändert ein Setter die Breite des Quaders.
Verhalten
Die innerhalb der Klasse definierten (nicht statischen) Methoden können nur auf einem Objekt ausgeführt werden. Anders formuliert: Das Objekt führt die Methode aus. Das Verhalten der Methode ist abhängig vom Zustand des Objektes, das die Methode ausführt. So gibt z.B. die oben erwähnte getVolume()
-Methode für jedes Objekt einen anderen Wert zurück. Das Ergebnis ist also abhängig vom Zustand (den Attributen) des Objektes.
Lebenszyklus
Ein Objekt repräsentiert Daten. Diese liegen im Speicher des Rechners. Wird ein Objekt erzeugt, so verbraucht es den Speicher des Rechners, indem entsprechend der Größe des Objektes Speicher für dieses reserviert wird. Wird ein Objekt nicht mehr benötigt, so wird der von ihm reservierte Speicher wieder freigegeben.
Instanziierung
siehe auch: Instanziierung
Ein Objekt wird erzeugt, oder instanziiert, indem sein Konstruktor mit dem Schlüsselwort new aufgerufen wird: new Object();
.
Damit existiert ein Objekt immer erst zur Laufzeit des Programms.
Freigabe
Ein Objekt verbleibt so lange im Speicher des Rechners, wie das ausführende Programm noch eine Referenz auf das Objekt verwaltet. Das heißt, ein Objekt wird nur dann gelöscht, wenn es nicht mehr verwendet werden kann. Ein System der JVM, der Garbage Collector, gibt den Speicher dieses Objektes dann wieder frei.
Beispiele
1. Wird nur der Konstruktor eines Objektes aufgerufen, ohne das neue Objekt einer Variablen zuzuweisen, so wird es beim nächsten Durchlauf des Garbage Collectors wieder freigegeben:
new Cuboid(3.0,3.0,3.0);
2. Wird ein Objekt lokal in einer Methode in einer Variablen vermerkt und seine Referenz ansonsten nicht weiter nach Außen gegeben, so wird das Objekt nach Verlassen der Methode freigegeben:
[...] public void printVolume(double w, double h, double l){ Cuboid block = new Cuboid(w,h,l); System.out.println(block.getVolume()); } [...]
3. Ist ein Objekt Teil eines anderen Objektes, z.B. als Attribut, so existiert das Objekt genau so lange, wie das ihn beinhaltende Objekt existiert (solange seine Referenz weiterhin nicht an einen anderen erreichbaren Teil des Programms übergeben wurde):
public class CubeContainer { private Cuboid cube; public CubeContainer(double edge){ this.cube = new Cube(edge, edge, edge); } }
4. Wird ein Objekt als Parameter einer Methode erwartet und beim Aufruf dieser Methode instanziiert, so existiert seine Referenz innerhalb der aufgerufenen Methode. Wird die Referenz danach weiterhin nicht nach Außen gereicht, wird das Objekt nach dem Verlassen der Methode freigegeben.
[...] public void printCube(double edge){ System.out.println(new Cube(edge, edge, edge)); } [...]