Hallo allerseits,
ich habe ein kleines Problem mit meinen Objekten in Java: Ich hab zwei Hühner erschaffen, die munter gackern, scharren und Eier legen können. Und außerdem kann ein Huhn ein anderes attackieren, bis dieses keine Lebenspunkte mehr hat und stirbt. Jedenfalls sterben soll, denn leider gackert das Huhn nach seinem Tod munter weiter. Das Problem ist, dass Java soweit ich weiß keinen echten Destruktor für Objekte hat. Mit finalize() wird dem Garbage Collector ja nur empfohlen, das Objekt zu löschen. Aber der tuts nur, wenn er gerade Lust dazu hat. Selbes Spiel mit System.gc().
Das einzige, was funktioniert, ist der Aufruf von Elfi = null; um das Objekt Elfi zu löschen. Aber ich hab nicht rausgefunden, wie ich das aus einem anderen Objekt heraus bewerkstelligen kann. Aber seht selbst:
Main.java
Code java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
| /*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package zoo;
/**
*
* @author Frezl
*/
public class Main {
// METHODEN
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// Hühner
Huhn Elfi = new Huhn("Elfriede", 430, "braun", 2);
Huhn Berta = new Huhn("Berta", 410, "weiß", 3);
// Leben auf dem Hühnerhof
Elfi.gackern();
Berta.gruessen();
Berta.scharren();
Berta.attackieren(Elfi);
Berta.attackieren(Elfi);
Berta.scharren();
Elfi.gackern();
Elfi.gackern();
Berta.attackieren(Elfi);
Berta.attackieren(Elfi);
Berta.attackieren(Elfi);
Berta.attackieren(Elfi);
Berta.scharren();
Elfi.gackern();
Elfi.gackern();
Berta.attackieren(Elfi);
Berta.attackieren(Elfi);
Berta.attackieren(Elfi);
Berta.attackieren(Elfi); // hier stirbt Elfi, da die Lebenspunkte auf 0 sinken
// leider lebt der Geist von Elfi aber munter weiter :-P
Elfi.gackern();
Elfi.scharren();
Ei Osterei = Elfi.eiLegen();
// erst wenn Gott das Huhn mit eigener Hand tötet, ist es erlöst
Elfi = null;
Elfi.gackern(); // und kann auch nicht mehr gackern... (Was zu einer NullPointerException führt)
}
} |
Huhn.java
Code java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
| /*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package zoo;
/**
*
* @author Frezl
*/
public class Huhn {
// ATTRIBUTE
String Name;
float Gewicht;
String Farbe;
int Alter;
int Lebenskraft;
// METHODEN
void gackern() {
System.out.println(Name + ": gack");
}
void gruessen() {
System.out.println(Name + ": Hallo, ich bin " + Name + ".");
}
void scharren() {
System.out.println(Name + ": *scharr*");
}
void attackieren(Huhn Huhn) {
Huhn.Lebenskraft = Huhn.Lebenskraft - 10;
System.out.println("> " + Huhn.Name + " hat jetzt noch " + Huhn.Lebenskraft + " Lebenspunkte.");
if(Huhn.Lebenskraft <= 0) {
Huhn.finalize(); // Hier soll das attackierte Huhn getötet werden
System.out.println("> " + Huhn.Name + " wurde von " + this.Name + " getötet.");
}
}
Ei eiLegen() {
System.out.println("> " + Name + " hat ein Ei gelegt.");
return new Ei("braun", 45);
}
// KONSTRUKTOR
Huhn(String Name, float Gewicht, String Farbe, int Alter) {
this.Name = Name;
this.Gewicht = Gewicht;
this.Farbe = Farbe;
this.Alter = Alter;
this.Lebenskraft = 100;
System.out.println("> " + Name + " wurde geboren.");
}
// DESTRUKTOR
@Override
protected void finalize() {
System.out.println(Name + ": *röchel*");
System.out.println("> " + Name + " ist gerade gestorben.");
}
} |
Ei.java
(Der Vollständigkeit halber, obwohl diese Klasse mit dem Problem nix zu tun hat)
Code java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| /*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package zoo;
/**
*
* @author Frezl
*/
public class Ei {
// ATTRIBUTE
String Farbe;
float Gewicht;
// KONSTRUKTOR
Ei(String F, float G) {
Farbe = F;
Gewicht = G;
}
} |
Weiß jemand Rat? Oder muss ich tatsächlich darauf warten, bis sich der Sensenman bemüßigt fühlt, das Huhn von seinen Leiden zu erlösen?
Gruß und Dank,
Frezl
Geändert von Frezl (21.03.10 um 22:53 Uhr)
Wenn du das Gefühl hast "Cool, der Kerl konnte mir echt helfen!", dann teil es mir mit, indem du mich entsprechend bewertest!
@mccae:
Wenn du mir sagst, wo ich die Tags finde, verwende ich sie gerne...
So wie du mir das beschreibst, finde ich das überhaupt nicht intuitiv. Die OOP soll es dem Programmierer doch erleichtern, die Wirklichkeit im Code abzubilden. In der Wirklichkeit ist es aber nicht so, dass das Huhn denkt "Bin ich tot? Ja? Dann darf ich jetzt nicht mehr atmen.", sondern es ist einfach tot und tut garnix mehr. Fertig. Für micht sind das nicht Äpfel und Birnen. Das Objekt im Code ist das Huhn aus dem echten Leben. Und dieses Huhn muss ich doch irgendwie töten können, wenn ich es will. Sonst hab ich als Programmierer ja gar keine Kontrolle mehr über mein Programm. Außerdem verkompliziert es die Sache doch ungemein, wenn ich in jeder Funktion erst mal prüfen muss, ob das Objekt noch existiert oder nicht. Viel sinnvoller ist es doch, dass beim Aufruf einer Methode eines nicht existierenden Objekts eine Exception geworfen wird. So wie das im echten Leben auch wäre. Wenn das Huhn atmet, obwohl es tot ist, dann ist was paradoxes passiert und das Universum kollabiert. Oder sowas. Keine Ahnung, ich gehe davon aus, dass das im echten Leben nicht passieren kann, weil die Natur ein gutes Exception Handling hat...
Viele Grüße,
Frezl
Wenn du das Gefühl hast "Cool, der Kerl konnte mir echt helfen!", dann teil es mir mit, indem du mich entsprechend bewertest!
Hey Kai,
danke für den Tipp mit den Java-Tags!
Mit der Exception hast du mich glaube ich falsch verstanden. Ich will keine Exception, wenn das Huhn stirbt. Die Exception soll dann geworfen werden, wenn ich das tote Huhn gackern lassen will. Wenn ich also eine Methode in einem nicht existierenden Objekt aufrufen will. Und das genau passiert ja auch, wenn ich in meiner main-Funktion den Pointer des Objekts auf null setzte:
Code java:
1
2
3
4
5
6
7
| public static void main(String[] args) {
// [...]
Elfi = null;
Elfi.gackern(); // hier wird logischerweise eine Exception geworfen.
} |
Was mir aber immer noch fehlt ist ein Destruktor, mit dem sich das Objekt selbst zerstören kann. Dass ich mit dem Aufruf das Objekt Elfi zerstöre. Und außerdem eine Möglichkeit, wie ein Objekt ein anderes zerstören kann, sodass ebenfalls das Objekt Elfi zerstört.
Ist es nachvollziehbar, um was es mir geht?
Viele Grüße,
Fred
Geändert von Frezl (21.03.10 um 23:09 Uhr)
Wenn du das Gefühl hast "Cool, der Kerl konnte mir echt helfen!", dann teil es mir mit, indem du mich entsprechend bewertest!
Das ist aber nicht Java-Stil, jedenfalls nicht soweit ich das beurteilen kann. Wie schon gesagt wurde, kannst du intern nen Flag setzen, wenn ein Huhn tot ist und dann wird eben darauf reagiert. Wenn du willst, kannst du dir eine eigene Exception schreiben (vielleicht HuhnIstTotException), die bei jeder Methode des Huhns geworfen werden kann. Ob das sinnig ist, ist eine andere Sache, ich glaube eleganter wäre einfach zu prüfen, ob das Flag "tot" gesetzt ist. Andererseits ersparrt man sich mit der Exception das explizite Prüfen des Flags, aber man muss dann eben Exception-Handling betreiben.
Dein Problem ist, dass du versuchst etwas zu "pulverisieren". Jetzt denk aber mal nach. Wenn ein Huhn tot ist, dann ist es doch nicht weg. Sein Körper ist weiterhin vorhanden, es reagiert nur auf nichts. Genauso ist es auch mit den Objekten. Erst wenn du das Objekt nirgeds mehr referenzierst, dann wird es vom GC verworfen.
Man sagt, das Schwert eines Samurai sei seine Seele ...
Mit den Beiträgen ist es wie mit Schwertern: Je besser die Rohstoffe sind und je öfter man diese bearbeitet, desto hochwertiger sind sie.
Das Schmieden ist eine Kunst; Das Schreiben auch ;)
Mkay, wenn ich das Huhn stofflich betrachte. Aber das was entscheidet, ist das Gehirn des Huhns und das ist tot, oder auch im Hühnerhimmel. Aber vielleicht ist es auch etwas übertrieben von mir, die Realität 1:1 abbilden zu wollen. Denn wenn es so ist, dürfte ich auch das Huhn nicht dazu zwingen, zu gackern... Denn das müsste das Huhn dann von selbst tun, wenn es will.
Halten wir also fest: In Java gibt es keinen echten Destruktor. Hab ich das soweit korrekt verstanden?
Trotzdem verstehe ich nicht, warum es keine Möglichkeit gibt, gerade diesen letzten Pointer zu löschen. Wenn ich es richtig verstehe, gibt es ja zwei Pointer, die auf das Huhn Elfriede zeigen.
Zum einen gibt es die Variable Elfi, die auf das Huhn Elfriede zeigt:
Code java:
1
| Huhn Elfi = new Huhn("Elfriede", 430, "braun", 2); |
Zum anderen gibt es dann den internen Zeiger Huhn des Objekts Berta, der in diesem Moment auf das Huhn Elfriede zeigt:
Code java:
1
| Berta.attackieren(Elfi); |
Und genau aus dieser Methode
Code java:
1
2
3
4
5
6
7
8
9
| void attackieren(Huhn Huhn) {
Huhn.Lebenskraft = Huhn.Lebenskraft - 10;
System.out.println("> " + Huhn.Name + " hat jetzt noch " + Huhn.Lebenskraft + " Lebenspunkte.");
if(Huhn.Lebenskraft <= 0) {
// Hier soll das attackierte Huhn getötet werden
System.out.println("> " + Huhn.Name + " wurde von " + this.Name + " getötet.");
}
} |
heraus, will ich ja den Pointer Elfi = null setzen.
Ist das ganz sicher überhaupt nicht möglich, oder steh ich nur auf dem Schlauch? Das einzige, was ich bis jetzt geschafft hab, war den internen Zeiger Huhn = null zu setzen. Aber das hilft mir leider nicht weiter :-P
Viele Grüße,
Frezl
Geändert von Frezl (21.03.10 um 23:31 Uhr)
Wenn du das Gefühl hast "Cool, der Kerl konnte mir echt helfen!", dann teil es mir mit, indem du mich entsprechend bewertest!
Du sprichst zwar von Pointern, aber hast ihre Funktionsweise scheinbar noch nicht begriffen. Pointer zeigen auf eine bestimmte Adresse. In Java machen das Objekte auch. Der Punkt ist aber, dass die Pointer auch nur Variablen sind. Nur weil du einen solchen Zeiger mit null inistialisierst (oder löschst, kommt drauf an, aus welchem Winkel man die Sache sieht) ist das Originalobjekt doch nicht verschwunden. Lediglich die Referenz von der Variable zu dem Objekt ist verschwunden, alle anderen aktiven Referenzen bleiben aber weiterhin bestehen, auf sie hat das keine Auswirkungen.
Verstehste was ich meine? Ob nun Pointer-Variablen in C/C++ oder Objektvariablen in Java, beim Initialisieren mit null passiert nicht mehr als dass du das "Seil", das die Variable mit dem Objekt verbindet, "durchschneidest". Das Objekt selbst ist aber rein formal noch da.
In C/C++ kann man explizit den Speicher dann freigeben, muss man sogar, wenn man der Meinung ist, dass man das Objekt nicht mehr braucht. In Java gibt es den Luxus, dass der GC einem diese Arbeit abnimmt, einzige Bedingung ist aber, dass es keine Referenzen geben darf, die auf das Objekt zeigen. Und natürlich muss der GC aufräumen, aber das ist mehr oder weniger Zufall. Für den Ablauf des Programms ist das aber nicht wichtig, weil sobald keine Referenz mehr vorhanden ist, ist das Objekt so zu sagen "tot", ob es im Orbit des RAMs rumschwebt oder wirklich verworfen wurde interessiert dabei keinen mehr, weil man darauf ohnehin nicht mehr zugreifen kann, da alle Referenzen getrennt wurden.
Man sagt, das Schwert eines Samurai sei seine Seele ...
Mit den Beiträgen ist es wie mit Schwertern: Je besser die Rohstoffe sind und je öfter man diese bearbeitet, desto hochwertiger sind sie.
Das Schmieden ist eine Kunst; Das Schreiben auch ;)
Richtig, ist nicht ganz das Selbe, es ging mir dabei aber auch nur um die Referenzen. Nur weil eine Referenz erlischt, stirbt nicht das Original, es wird nur eine Verbindung gekappt. Alle anderen Verbindungen, sofern welche vorhanden sind, bleiben weiterhin bestehen und lassen das Objekt "leben".
Man sagt, das Schwert eines Samurai sei seine Seele ...
Mit den Beiträgen ist es wie mit Schwertern: Je besser die Rohstoffe sind und je öfter man diese bearbeitet, desto hochwertiger sind sie.
Das Schmieden ist eine Kunst; Das Schreiben auch ;)
@ Akeshihiro:
Okay, das mit den Pointern stimmt natürlich. Das hab ich so genau nicht beachtet. Aber im Prinzip würde es mir ja schon reichen, wenn das Objekt für mein Programm verschwunden ist, also alle Seile zum Jenseits gekappt sind und das Huhn im Hühnerhimmel (= irgendwo im Speicher) rumschwebt. Dann isses mir auch wurscht, wanns letztendlich im Fegefeuer (= GC) landet.
@ Kai008:
Kannst du mir ein Beispiel geben, wie ich das implementieren kann? Ich steh da grad n bissel aufm Schlauch :-P
Viele Grüße und besten Dank euch!
Frezl
Wenn du das Gefühl hast "Cool, der Kerl konnte mir echt helfen!", dann teil es mir mit, indem du mich entsprechend bewertest!
Aaahja, interessant. Danke für den Post! Ich werds mir morgen mal genauer anschaun... Aber jetzt erst mal gute Nacht! *gähn*
Wenn du das Gefühl hast "Cool, der Kerl konnte mir echt helfen!", dann teil es mir mit, indem du mich entsprechend bewertest!
Hallo, liebe Leute,
da mein eigentliches Problem ("Objekt soll anderes Objekt zerstören") an der Realität* vorbeizugehen schein, habe ich eine andere Lösung gefunden: Es gibt eine Klasse Gott, die andere Objekte erschaffen kann. Außerdem verwaltet sie das BuchDesLebens, in dem alle lebenden Objekte verzeichnet sind. Aus dieser Klasse wird das Objekt derHerr instanziert, der bis in alle Ewigkeit über seine Schöpfung wacht.
Das ganze sieht dann so aus:
Main.java
Code java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
| /*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package zoo002;
/**
*
* @author Frederik
*/
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// Gott wird erschaffen...
Gott DerHerr = new Gott("DerHerr");
// ...und beginnt mit der Arbeit.
DerHerr.start();
// als erstes erschafft er ein paar Hühner
Huhn Elfi = DerHerr.erschaffeHuhn("Elfriede", 730, "braun");
Huhn Berta = DerHerr.erschaffeHuhn("Berta", 523, "weiß");
// Die Hühner leben friedlich auf dem Bauernhof
Elfi.gruesse();
Berta.gruesse();
Elfi.scharre();
Berta.gackere();
Ei Osterei = Berta.legeEi();
// Bis der Herr beschließt, dass es genug ist und ein Huhn tötet
Elfi = DerHerr.toeteLebewesen(Elfi); // hier fände ich eine Lösung mit Out-Parameter intuitiver!
// Elfi.scharre(); // und hier wird eine Exception geworfen, weil das Huhn ja tot ist :-)
// weil es jetzt aber Langweilig ist auf der Erde, schafft Gott wieder ein zweites Huhn
Huhn Gundi = DerHerr.erschaffeHuhn("Kunigunde", 620, "schwarz");
// und das Leben geht weiter...
Gundi.gruesse();
// ...bis Gundi eines Tages völlig grundlos auf Berta losgeht
Gundi.attackiere(Berta);
Gundi.attackiere(Berta);
Gundi.attackiere(Berta);
Gundi.attackiere(Berta);
Gundi.attackiere(Berta);
Gundi.attackiere(Berta);
Gundi.attackiere(Berta);
Berta.gackere();
Gundi.attackiere(Berta);
Gundi.attackiere(Berta);
Gundi.attackiere(Berta); // hier stirbt Berta
}
} |
Lebewesen.java:
Code java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
| /*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package zoo002;
/**
*
* @author Frederik
*/
public class Lebewesen {
// ATTRIBUTE
private String Name;
private int Lebenskraft;
// GETer & SETer
void setName(String x) {
Name = x;
}
String getName() {
return Name;
}
void setLebenskraft(int x) {
Lebenskraft = x;
}
void erhöheLebenskraft(int x) {
Lebenskraft += x;
}
void erniedrigeLebenskraft(int x) {
Lebenskraft -= x;
}
int getLebenskraft() {
return Lebenskraft;
}
// DESTRUKTOR
@Override
protected void finalize() {
System.out.println(this.getName() + "> ist gerade gestorben.");
}
} |
Huhn.java:
Code java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
| /*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package zoo002;
/**
*
* @author Frederik
*/
public class Huhn extends Lebewesen {
// ATTRIBUTE
private float Gewicht;
private String Farbe;
// METHODEN
void gackere() {
System.out.println(getName() + ": *gack* *gack*");
}
void gruesse() {
System.out.println(getName() + ": Hallo, ich bin " + getName() + ".");
}
void scharre() {
System.out.println(getName() + "> scharrt auf dem Boden.");
}
void attackiere(Huhn Huhn) {
Huhn.erniedrigeLebenskraft(10);
if(Huhn.getLebenskraft() <= 0) {
System.out.println(getName() + "> hat " + Huhn.getName() + " getötet!");
// Wie im echten Leben! Da die Lebenskraft des Gegners <= 0 ist, meint das Huhn, es hätte seinen Gegner getötet.
// Aber wirklich tot ist das Huhn erst, wenn Gott es von seinen Leiden erlöst hat.
// Denn vielleicht lässt er es ja wiederauferstehen?
} else {
System.out.println(getName() + "> hat " + Huhn.getName() + " attackiert!");
}
}
Ei legeEi() {
System.out.println(getName() + "> hat ein Ei gelegt.");
return new Ei("braun", 45);
}
// KONSTRUKTOR
Huhn(String Name, float Gewicht, String Farbe) {
this.setName(Name);
this.setLebenskraft(100);
this.Gewicht = Gewicht;
this.Farbe = Farbe;
System.out.println(this.getName() + "> wurde soeben geboren.");
}
} |
Gott.java
Code java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
| package zoo002;
import java.util.ArrayList;
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* @author Frederik
*/
public class Gott extends Thread { // eigentlich würde hier "extends Lebewesen impements Runnable" besser passen!
// ATTRIBUTE
String Name;
private ArrayList<Lebewesen> BuchDesLebens;
// METHODEN
@Override
public void run() {
// Gott macht bis in alle Ewigkeit nichts anderes, als seine Schöpfung zu überwachen
while(true) {
for(int i = 0; i < (BuchDesLebens.size() - 1); i++) {
Lebewesen Delinquent = BuchDesLebens.get(i);
if(Delinquent.getLebenskraft() <= 0) {
this.toeteLebewesen(Delinquent);
}
}
}
}
Huhn erschaffeHuhn(String Name, int Gewicht, String Farbe) {
// Das, was Gott am liebsten macht - ein neues Huhn erschaffen:
Huhn neuesHuhn = new Huhn(Name, Gewicht, Farbe);
// jetzt kommt der Verwaltungskram:
BuchDesLebens.add(neuesHuhn); // Huhn ins Buch des Lebens eintragen
// Das neue Huhn ins Leben entlassen:
return neuesHuhn;
}
Huhn toeteLebewesen(Lebewesen altesLebewesen) {
BuchDesLebens.remove(altesLebewesen);
altesLebewesen.finalize();
System.out.println(this.getName() + "> hat " + altesLebewesen.getName() + " von seinen Leiden erlöst.");
return null;
}
// KONSTRUKTOR
Gott(String Name) {
this.setName(Name);
BuchDesLebens = new ArrayList(0);
}
} |
Jetzt gibt es zumindest mal ein Konstrukt, das über Leben und Tod der einzelnen Objekte wacht. Wie kann ich es aber realisieren, dass derHerr darüber wacht, was ein Objekt darf und was nicht? Ich stell mir das so vor, dass Berta scharren will (Berta.scharre()
. derHerr schaut dann in sein BuchDesLebens und sieht "oh, da steht keine Berta drin, also ist sie tot". Und dann verbietet er Berta das Scharren.
Du verstehst, was ich meine? Dass also nicht das Objekt selbst in jeder Methode prüft, ob es die noch ausführen darf oder nicht. Vielmehr soll das Objekt derHerr managen, ober ein anderes Objekt überhaupt noch irgendwas darf oder nicht. egal was das ist...
Viele Grüße,
Frezl
---------------------------
* Wer diesen Satz aufmerksam liest, merkt, dass ich ganz nebenbei die Existenz Gottes bewiesen habe...
Wenn du das Gefühl hast "Cool, der Kerl konnte mir echt helfen!", dann teil es mir mit, indem du mich entsprechend bewertest!