Zur Haupt­na­vi­ga­ti­on sprin­gen [Alt]+[0] Zum Sei­ten­in­halt sprin­gen [Alt]+[1]

Le­bens­zy­klus von Ob­jek­ten

Er­zeu­gen von Ob­jek­ten

Nach­dem nun ge­klärt ist, was Ob­jek­te und Klas­sen sind und wie man ge­eig­ne­te Klas­sen­ent­wür­fe fin­det, wird in die­sem Ka­pi­tel dar­ge­stellt wie Java mit Ob­jek­ten um­geht. Vie­les davon lässt sich im Prin­zip aber auch auf an­de­re Pro­gram­mier­spra­chen über­tra­gen.

De­kla­riert man in Java eine Va­ria­ble, so wird je nach Typ der Va­ria­ble ein ge­nü­gend gro­ßer Spei­cher­be­reich re­ser­viert: für eine int-Va­ria­ble bei­spiels­wei­se 32bit, für eine char-Va­ria­ble 16bit. Dies ist bei Ob­jek­ten an­ders. De­kla­riert man mit

CRT_Fernseher fernseher1;

die Va­ria­ble fern­se­her1 vom Typ CRT_­Fern­se­her, so wird da­durch kein Spei­cher­platz für ein CRT_­Fern­se­her-Ob­jekt re­ser­viert, son­dern nur für eine Re­fe­renz auf ein Ob­jekt. Diese Va­ria­ble spei­chert also nur einen Ver­weis auf ein Ob­jekt und nicht das Ob­jekt selbst. Der für eine Re­fe­renz­va­ria­ble re­ser­vier­te Spei­cher ist immer gleich groß, un­ab­hän­gig von der Art des Ob­jek­tes auf das die Va­ria­ble zei­gen soll.

Erst durch den new-Be­fehl wird im Heap (einem spe­zi­el­len Spei­cher­be­reich für die Ob­jek­te) Spei­cher­platz re­ser­viert1. Die Re­fe­renz­va­ria­ble ver­weist dann auf die­sen Spei­cher­be­reich. Dies kann man sich fol­gen­der­ma­ßen vor­stel­len:

Eine pri­mi­ti­ve Va­ria­ble ist wie eine Kiste mit Auf­schrift (=Name der Va­ria­ble). Die Größe der Kiste wird durch den Va­ria­blen­typ fest­ge­legt. Der In­halt der Kiste gibt den Wert der Va­ria­ble an.

int i;
Kiste
char c;
Kiste

Eine Re­fe­renz­va­ria­ble ist ge­nau­so eine Kiste. Zu Be­ginn zeigt sie auf nichts (null-Poin­ter).

Katze k;
Kiste

Erst wenn ihr ein Wert zu­ge­wie­sen wird, zeigt sie auf ein kon­kre­tes Ob­jekt. Häu­fig ent­ste­hen Feh­ler da­durch, dass einer Re­fe­renz­va­ria­blen kein Ob­jekt zu­ge­wie­sen wird, bzw. gar kein Ob­jekt er­zeugt wird. Ver­sucht man dann auf das Ob­jekt zu­zu­grei­fen, er­hält man eine null-poin­ter ex­cep­ti­on.

k = new Katze("Mauzi");
Verdeutlichung anhand Kiste und Wolke

In Java sind auch Ar­rays Ob­jek­te. Dies er­kennt man daran, dass auch der Spei­cher­platz für Ar­rays mit dem new Ope­ra­tor re­ser­viert wer­den muss. Es wird dann ein Spei­cher­be­reich im Heap re­ser­viert, der für die an­ge­ge­be­ne An­zahl an Va­ria­blen des Grund­typs aus­rei­chend ist. Au­to­ma­tisch haben die Array-Ob­jek­te dann auch ein At­tri­but length.

int[] nr = new int[5];
Verdeutlichung anhand Kiste und Wolke

Na­tür­lich kön­nen auch Ar­rays er­zeugt wer­den, die als Grund­typ eine Re­fe­renz­va­ria­ble haben. Ge­ra­de dann kommt es oft zu null-Poin­ter ex­cep­ti­ons, wenn nicht alle Spei­cher­plät­ze mit Re­fe­ren­zen auf exis­tie­ren­de Ob­jek­te be­legt wer­den.

Tier[] ti = new Tier[5];
ti[3] = new Katze(“Mauzi“);
ti[1] = new Katze(“Freddi“);
Verdeutlichung anhand Kiste und Wolke

Ma­ni­pu­la­ti­on von Ob­jek­ten

Die un­ter­schied­li­che Be­hand­lung von pri­mi­ti­ven Va­ria­blen und Re­fe­renz­va­ria­blen hat auch Aus­wir­kun­gen auf die Pro­gram­mie­rung. So führt bei­spiels­wei­se fol­gen­der Ver­gleich in der Regel nicht zum ge­wünsch­ten Er­geb­nis, ob­wohl er sich kor­rekt kom­pi­lie­ren lässt.

Katze k1 = new Katze("Mauzi");
Katze k2 = new Katze("Mauzi");
if (k1 == k2) {....}
Verdeutlichung anhand Kiste und Wolke

Die bei­den Re­fe­renz­va­ria­blen zei­gen auf ver­schie­de­ne Ob­jek­te. Damit kann der Ver­gleich nicht po­si­tiv aus­fal­len, auch wenn alle At­tri­but­wer­te iden­tisch sind. Die At­tri­but­wer­te müs­sen ein­zeln ver­glei­chen wer­den. Selbst fol­gen­der Ver­gleich schlägt noch fehl:

if (k1.rufname == k2.rufname) {...}

Diese bei­den Strings wür­den nicht als iden­tisch er­kannt wer­den, da auch Strings in Java Ob­jek­te und keine ein­fa­chen Va­ria­blen sind2. Daher wird die Typ­be­zeich­nung String groß­ge­schrie­ben. Die Si­tua­ti­on auf dem Heap sieht also in Wirk­lich­keit eher so aus:

Verdeutlichung anhand Kiste und Wolke

Ein Ver­gleich der bei­den String-Re­fe­renz­va­ria­blen muss also fehl­schla­gen. Die Klas­se String stellt aber eine Viel­zahl von Me­tho­den zur Ver­fü­gung. Mit der spe­zi­el­len Me­tho­de com­pa­re­To kön­nen tat­säch­lich die In­hal­te der Strings ver­gli­chen wer­den.

if (k1.rufname.equals(k2.rufname)) {...}

Auch beim Ver­än­dern von Va­ria­blen­wer­ten spielt dies eine Rolle:

int alter1 = 5;
int alter2 = alter1;

Katze k1 = new Katze(„Mauzi“);
k1.alter = 5;
Katze k2 = k1;

Es ist klar, dass nun in al­ter2 der Wert 5 und in k2.​alter auch der Wert 5 steht. Än­dert man aber nun den Wert von al­ter2, bzw. k2.​alter, dann hat dies un­ter­schied­li­che Aus­wir­kun­gen. Wird al­ter2 ge­än­dert, so be­hält al­ter1 den Wert 5, da es sich um un­ab­hän­gi­ge Va­ria­blen han­delt, deren Wert nur zu­fäl­lig am An­fang gleich ge­setzt wurde. Än­dert man aber k2.​alter auf 6, so ist au­to­ma­tisch auch k1.​alter gleich 6, da beide Re­fe­renz­va­ria­blen auf das glei­che Ob­jekt ver­wei­sen. Bei die­sem Ob­jekt wird der At­tri­but­wert ge­än­dert.

Verdeutlichung anhand Kiste und Wolke

Lö­schen von Ob­jek­ten

Um das Lö­schen von Ob­jek­ten braucht man sich in Java glück­li­cher­wei­se nicht zu küm­mern. Die Java-Ma­schi­ne merkt sich, wel­che Ver­wei­se auf ein Ob­jekt exis­tie­ren. So­bald kein Ver­weis mehr auf ein Ob­jekt exis­tiert, kann es nicht mehr an­ge­spro­chen wer­den. Daher ist es über­flüs­sig ge­wor­den. Der Gar­ba­ge Collec­tor von Java sorgt daher in re­gel­mä­ßi­gen Ab­stän­den dafür, dass un­nütz ge­wor­de­ne Ob­jek­te ge­löscht und der Spei­cher­platz frei ge­ge­ben wird.

Möch­te man einen Ver­weis auf ein Ob­jekt ent­fer­nen, setzt man die Re­fe­renz­va­ria­ble auf den Wert null.

k1 = null;

An­mer­kung: In an­de­ren Pro­gram­mier­spra­chen müs­sen Ob­jek­te manch­mal durch den Auf­ruf des De­struk­tors ge­löscht wer­den.

Li­te­ra­tur­tipp: In „Java – von Kopf bis Fuß“ (Kathy Si­er­ra, O'Reil­ly Ver­lag) ist der Le­bens­zy­klus von Ob­jek­ten sehr gut dar­ge­stellt und be­schrie­ben. Es fin­den sich dort auch ei­ni­ge Auf­ga­ben, die sich auch für die Schu­le eig­nen.


1 Die lo­ka­len Va­ria­blen und Pa­ra­me­ter einer Me­tho­de legt Java auf dem Stack ab. Bei jedem Me­tho­den­auf­ruf wird ein Stack-Frame auf den Stack ab­ge­legt, der Platz für die lo­ka­len Va­ria­blen die­ser Me­tho­de und ei­ni­ge Zu­satz­da­ten bie­tet.

2 String-Ob­jek­te müs­sen nicht un­be­dingt mit dem new-Ope­ra­tor er­zeugt wer­den, son­dern kön­nen auch durch Zu­wei­sung einer Kon­stan­ten im­pli­zit er­zeugt wer­den.

 

 

Le­bens­zy­klus von Ob­jek­ten: Her­un­ter­la­den [odt][61 KB]

 

Wei­ter zu Klas­sen­ent­wurf