# OOP Bug in Java?



## Kaffeebohne (2. Jan 2007)

Hi Leute,


Ist es ein Bug in Java 1.6 das man Attribute, bzw deren Werte nicht korrekt überschreiben kann? Wenn ich eine Klasse erweitere und ein Attribut überschreibe, hat diese Kindklasse trotzdem noch den Wert der Vaterklasse, wenn ich eine Methode ausführe, welche in der Vaterklasse definiert ist.



MFG & Frohes Neues

Kaffeebohne


----------



## Roar (2. Jan 2007)

zwar keine ahnung was du meinst, aber 
> OOP Bug
sicher nich :roll:


----------



## Eldar (2. Jan 2007)

Du meinst du hast eine Kindklasse in der du ein vererbtes Attribut überschreibst. Wenn du dann aus einem Objekt der Kindklasse eine Methode aufrufst die nur in der Vaterklasse definiert ist, hat das Attribut noch den Wert aus der Vaterklasse?
So richtig erklärt? Dann bitte mal den Code den du hast posten.
Entweder bist du nihcht ineinem Objekt der kindklasse sondern der Vaterklasse, oder du hast beim Attribut was übersehen.


----------



## Kaffeebohne (2. Jan 2007)

Hmm, also ich hab das hier mal gepostet:

http://www.entwickler-blog.de/archiv/162-Bug-in-der-Vererbung-von-Java.html#extended


----------



## The_S (2. Jan 2007)

Verwende in deiner Elternklasse getter und setter und greife so auf die Variable zu. Dann funktioniert es und ist außerdem besserer stil ;-) . Falls du das nicht möchtest kannst du auch über das super-Statement auf die Variable deiner Elternklasse zugreifen.


----------



## byte (2. Jan 2007)

> ```
> // Hier überschreibe ich den Wert!
> protected int maximaleGeschwindigkeit  = 300;
> ```



Da liegt der Hund begraben. Du überschreibst die Variable nicht sondern Du überlagerst sie in der Unterklasse. Sowas sollte man generell vermeiden, weil es genau zu solchen Verwirrungen führen kann.

PS: Crossposting wird nicht so gerne gesehen...


----------



## Kaffeebohne (2. Jan 2007)

Eigentlich will ich ja gar nicht auf den Wert der Elternvariable zugreifen, sondern den aus der Kindklasse.

Deine Vorschlag, mit dem Getter und Settern zu arbeiten, hat nicht den gewünschten Erfolg. Ich definiere ja in der Elternklasse die Getter und Setter und nicht nochmal in der Kindklasse.

Nichtsdestotrotz hab ichs ausprobiert und habe noch etwas komisches festgestellt:


```
public class Auto {
    
    protected int maximaleGeschwindigkeit = 0;
    
    
    /** Creates a new instance of Car */
    public Auto() {
       
    }
    
    public void beschleunige() {
        System.out.println("Beschleunige bis: " + getMaximaleGeschwindigkeit() );
        System.out.println("Ich bin ein: " + this );
    }
    
    
    public int getMaximaleGeschwindigkeit(){
        return maximaleGeschwindigkeit;
    }
}
```

Die Ausgabe ist dann:


Ich fahre maximal: 300
Beschleunige bis: 0
Ich bin ein: test.Mercedes@addbf1


Es ist also ein Mercedes


----------



## byte (2. Jan 2007)

Siehe oben...

Entferne einfach die Variable in der Unterklasse und setze den Wert der Geschwindigkeit im Konstruktor von Mercedes. Dann hast Du genau den gewünschten Effekt. Diese Art der Überlagerung ist in den meisten Fällen absolut sinnlos.

PS: Mit Gettern und Settern hat das herzlich wenig zu tun. :roll:


----------



## The_S (2. Jan 2007)

Kaffeebohne hat gesagt.:
			
		

> Eigentlich will ich ja gar nicht auf den Wert der Elternvariable zugreifen, sondern den aus der Kindklasse.



Alles andere würde auch keinen Sinn ergeben 



			
				Kaffeebohne hat gesagt.:
			
		

> Deine Vorschlag, mit dem Getter und Settern zu arbeiten, hat nicht den gewünschten Erfolg.



Also bei mir funktioniert das genau so wie es soll. Zeig doch mal deinen angepassten Code!



			
				Kaffeebohne hat gesagt.:
			
		

> Ich definiere ja in der Elternklasse die Getter und Setter und nicht nochmal in der Kindklasse.



Ja, das ist korrekt. Was ist dein Problem?



			
				Kaffeebohne hat gesagt.:
			
		

> Nichtsdestotrotz hab ichs ausprobiert und habe noch etwas komisches festgestellt:
> 
> 
> ```
> ...



Und wo ist die dazugehörige Main-Methode?


----------



## The_S (2. Jan 2007)

byto hat gesagt.:
			
		

> PS: Mit Gettern und Settern hat das herzlich wenig zu tun. :roll:



Ob er jetzt mit gettern und settern arbeitet oder einfach direkt ohne erneutes deklarieren auf die Variable zugreift ist letztendlich egal. Es ist einfach schöner auf eine Variable mit gettern und settern zuzugreifen sofern diese in einer anderen Klasse deklariert wurde. Auch wenn von dieser Klasse geerbt wird. Außerdem treten dadurch solche denkfehler (imho) viel seltener auf  .


----------



## Kaffeebohne (2. Jan 2007)

```
public class Auto {
    
    protected int maximaleGeschwindigkeit = 0;
    
    
    /** Creates a new instance of Car */
    public Auto() {
       
    }
    
    public void beschleunige() {
        System.out.println("Beschleunige bis: " + getMaximalGeschwindigkeit() );
        System.out.println("Ich bin ein: " + this );
    }
    
    
    public int getMaximalGeschwindigkeit(){
        return maximaleGeschwindigkeit;
    }
}



public class Mercedes extends Auto {
    
    
    /** Creates a new instance of Mercedes */
    public Mercedes() {
        maximaleGeschwindigkeit  = 300;
        System.out.println("Ich fahre maximal: " + maximaleGeschwindigkeit);
    }
    
 
}

public class Main {
    
    /** Creates a new instance of Main */
    public Main() {
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        
        Mercedes auto = new Mercedes();
        auto.beschleunige();
        
    }
    
}
```

@Hobbit
Hier ist der komplette Code.


@byto
Okay, wenn ich die Wertzuweisung im Konstruktor mache funktioniert es.

Aber warum ist das so? Wieso funktioniert es nicht, wenn ich das bei der Deklaration mache? Und wieso auch nur dann, wenn ich die Deklaration rausnehme?[/code]


----------



## Beni (2. Jan 2007)

Attribute konnte man noch nie überschreiben (was sollte das auch bringen? Wo wäre da ein Effekt zu sehen? Eine Zuweisung ergibt das gewünschte Verhalten.), nur Methoden lassen sich überschreiben.

(und wieder ein Blogeintrag, den die Welt nicht braucht... : - P )

[Edit: weil dann kein Attribut mehr überlagert wird]


----------



## The_S (2. Jan 2007)

Kaffeebohne hat gesagt.:
			
		

> @Hobbit
> Hier ist der komplette Code.



1. Hast du nur eine getter und keine setter
2. Rufst du folglich diese nicht vorhandene Setter-Methode auch nie auf, was aber relevant ist um die Geschwindigkeit zu setzen.


----------



## Kaffeebohne (2. Jan 2007)

@Beni
Gut, aber witzigerweise gibt ja der Kontruktor von Mercedes den "überschriebenen" Wert aus. Das finde ich paradox.

(du bist ja riesig  )


@Hobbit_Im_Blutrausch
Ich weiss, das ist auch nur ein Beispielcode. Komplett bezog sich auf den Geschriebenen. Nicht komplett  im Sinne von fertig


----------



## The_S (2. Jan 2007)

Ja, aber so kann es ja nicht gehen. Total unsinnig was du da machst :roll:


```
public class Auto {

   

    protected int maximaleGeschwindigkeit = 0;

   

    public Auto() {

    }

   

    public void beschleunige() {

        System.out.println("Beschleunige bis: " + maximaleGeschwindigkeit);

    }
    
    protected void setMax(int max) {
    	maximaleGeschwindigkeit = max;
    }

    protected int getMax() {
    	return maximaleGeschwindigkeit;
    }
}
```


```
public class Mercedes extends Auto {


 

    public Mercedes() {

setMax(300);
        System.out.println("Ich fahre maximal: " + getMax());
        

    }

   

}
```


```
public class Main {

 

    public Main() {

    }

   

    public static void main(String[] args) {       

        Mercedes auto = new Mercedes();

        auto.beschleunige();
        
        Audi auto2 = new Audi();
        auto2.beschleunige();

    }   

}
```


```
public class Audi extends Auto {

    // Hier überschreibe ich den Wert!


 

    public Audi() {

setMax(280);
        System.out.println("Ich fahre maximal: " + getMax());
        

    }

   

}
```


----------



## Kaffeebohne (2. Jan 2007)

In wie weit doch jetzt das unsinnig erscheint, ändert doch nichts an der Tatsache, dass das Verhalten komisch ist. Und nur darum gehts mir. Schau mal:


```
public class Mercedes extends Auto {
    protected int maximaleGeschwindigkeit  = 300;
    
    /** Creates a new instance of Mercedes */
    public Mercedes() {
        setMax(250);
        System.out.println("Ich fahre maximal: " + maximaleGeschwindigkeit);
    }
    
 
}
```

Ergibt:



> Ich fahre maximal: 300
> Beschleunige bis: 250


----------



## byte (2. Jan 2007)

Kaffeebohne hat gesagt.:
			
		

> @Beni
> Gut, aber witzigerweise gibt ja der Kontruktor von Mercedes den "überschriebenen" Wert aus. Das finde ich paradox.



Nochmal: Die Variable der Unterklasse überschreibt nicht die der Oberklasse, sondern sie überlagert sie. Es sind trotzdem zwei unterschiedliche Variablen, auf die man auch (wegen protected) auch direkten Zugriff hat. Es kommt jetzt darauf an, ob Du aus der Ober- oder Unterklasse auf die Variable zugreifst, welcher Wert zurückgegeben wird.

Methoden kannst Du hingegen tatsälich überschreiben. Da hängt es dann tatsächlich davon ab, mit welcher Unterklasse das Objekt gebunden ist, welche Methodenimplementierung aufgerufen wird.

Generell solltest Du obigen Fall immer vermeiden und nie Felder mit gleichem Namen überlagern.

@Hobbit: Wenn ich auf Variablen von Oberklassen zugreifen will, setze ich sie für gewöhnlich protected und greife direkt darauf zu, ohne Getter/Setter zu verwenden. Natürlich sind diese sinnvoll, aber eben nur, wenn ich nicht auf lokale Felder zugreife sondern auf Felder fremder Objekte.


----------



## The_S (2. Jan 2007)

Du deklarierst die Variable in jeder Unterklasse neu. Die Variable von deiner Superklasse bleibt davon unberührt. Es ergibt auch keinen Sinn in einer Kindklasse eine Variable zu überschreiben. Du kannst (sofern sie nicht privat ist) immer auf sie zugreifen. Hast du trotzdem zwei Variablen mit dem selben Namen kannst du auf die Variable der Superklasse mit dem super-Statement zugreifen.

[edit]

@Byto hm, ich hab das bis jetzt nur vereinzelt mit direktem Zugriff gesehen. Meist über protected getter und setter. Kann ja sein, dass die Variablen auch einer Validierung unterlaufen müssen (was hier natürlich nicht der Fall ist). Würde mich mal interessieren ob es dazu etwas offizielles von sun gibt  .


----------



## Beni (2. Jan 2007)

Oder anders gesagt: du "versteckst" die Variable aus "Auto" blos. Auto kennt natürlich seine eigenen Variablen, und ist dadurch unbeeindruckt.

Eine Methode hingegen kannst du "ersetzen" (=überschreiben), da kann auch die Oberklasse nichts dagegen tun.


----------



## byte (2. Jan 2007)

Hobbit_Im_Blutrausch hat gesagt.:
			
		

> [edit]
> 
> @Byto hm, ich hab das bis jetzt nur vereinzelt mit direktem Zugriff gesehen. Meist über protected getter und setter. Kann ja sein, dass die Variablen auch einer Validierung unterlaufen müssen (was hier natürlich nicht der Fall ist). Würde mich mal interessieren ob es dazu etwas offizielles von sun gibt  .



Du wirst z.B. in der Java API haufenweise protected Felder entdecken. Schau z.B. mal ins Field Summary von JComponent.

Edit: Wie greifst Du denn auf die Felder aus der direkten Klasse zu? Auch über Getter/Setter?


----------



## The_S (2. Jan 2007)

OK, überzeugt  . Aber falsch isses ja trotzdem net *auf Meinung besteh* 

[edit] Für wen ist das edit?


----------



## byte (2. Jan 2007)

Ne falsch ist es natürlich nicht. Ich find nur den Code leserlicher, wenn man direkt auf Felder zugreift. Ich nutze natürlich auch Getter/ Setter, aber nur für den Zugriff "von außen" bei public oder package private Feldern.

edit: edit war für dich!


----------



## The_S (2. Jan 2007)

Mich hätte auch alles andere schwer gewundert, wenn du bei public oder package keine getter und setter verwenden würdest  .

Zum edit: Jup, verwende intern natürlich auch die getter und setter anstelle direkt auf die Variable zuzugreifen (sonst wäre das Ganze ja wirklich sehr sinnlos). Eben weil es bei mir häufig vorkommt, dass ich noch diverse Validierungen/Änderungen an anderen Variablen zusätzlich benötige. Habs mir dann irgendwann angewöhnt das auch in Fällen anzuwenden, bei denen es eigentlich nicht nötig ist. Aber so bleibt der Code einheitlich  .


----------



## byte (2. Jan 2007)

Konsistentes Verhalten und plausible Argumente. Nix einzuwenden! :toll: Ich bleib aber bei meiner Angewohnheit.


----------



## Wildcard (2. Jan 2007)

byto hat gesagt.:
			
		

> @Hobbit: Wenn ich auf Variablen von Oberklassen zugreifen will, setze ich sie für gewöhnlich protected und greife direkt darauf zu, ohne Getter/Setter zu verwenden. Natürlich sind diese sinnvoll, aber eben nur, wenn ich nicht auf lokale Felder zugreife sondern auf Felder fremder Objekte.


Das ist so nicht richtig. Wenn eine Klasse selbst nur über getter/setter auf die eigenen Felder zugreift, dann hat das den Vorteil das das Verhalten durch überschreiben der getter/setter in der Unterklasse (sofern programmatisch sinnvoll) verändert werden kann.
Nimm als Beispiel einen TokenBuffer mit festem Token. Erb von diesem und überschreib die getSeperator Methode.
Wenn diesem ChangableTokenBuffer nun ein anderes Trennzeichen gestetz wurde und die Oberklasse konsequent die getter aufruft hast du eine erweiterte Funktionaliät durch überschreiben eines einzelnen getters.


----------



## byte (2. Jan 2007)

Naja ok, es gibt sicher Anwendungsfälle (habe ich ja auch nicht geleugnet). Aber deswegen präventiv immer und überall Getter/Setter verwenden? Ich weiss nicht...


----------



## Wildcard (2. Jan 2007)

Ehrlich gesagt:
Ich mach es meistens auch nicht so. 
Trotzdem ist es vom OOP Gedanken her sinnvoll und auch konsistenter.
Schließlich kann nicht automatisch davon ausgegangen werden, das derjenige der eine (möglicherweise fremde) Klasse bearbeitet sich an die gleichen Regeln hält wie sie für den 'Rest der Welt' getter/setter vorgeschrieben sind.


----------



## byte (2. Jan 2007)

Streng genommen müsste man immer getter/setter verwenden, da hast Du Recht. Ich ärgere mich auch immer wieder, dass Java nicht das Konzept der Properties aus C# übernimmt.


----------



## The_S (2. Jan 2007)

Mal wieder ein typischer Fall "richtig trotz Unwissenheit" meinerseits   .


----------

