Frage zur Vererbung

Status
Nicht offen für weitere Antworten.

DennisXX

Bekanntes Mitglied
Hallo Javagemeinde !

Ich habe mal eine Frage zur Vererbung in Java. Ich versuche folgendes Beispiel zu verstehen, ich hoffe, dass meine Erklärung zu diesem Szenario korrekt ist. Vielleicht kann das mal jemand von euch prüfen und mir bitte ein Feedback geben!?

Ich habe die vier folgenden Javaklassen:

Java:
public class A{

     public void g(){

     }

}

Java:
public class B extends A{

      public void g(){

      //Die Methode g() aus A soll von der Klasse B überschrieben werden

      }

}


Java:
public class C{

      public void f(A object){

      g();

      }

}

Java:
public class Appl{

      public static void main(String[] args){

      C obj = new C();

      obj.f(a);    //Übergabe mit einem Objekt der Klasse A
      obj.f(b);    //Übergabe mit einem Objekt der Klasse B    

}

Die Klasse C besitzt eine Methode f(), die wiederum die Methode g() aufrufen kann.

Die Frage: Warum ist es Möglich, der Methode f() ein Obejct der Klasse A und der Klasse B als formalen Parameter beim Aufruf mitzugeben und welche Methode g() wird letztendlich ausgeführt.

Meine Vermutung: Das liegt nur daran, weil die Klasse B die Klasse A erweitert, daher ist eine Referenz der Klasse B zuweisungskompatibel zu einem formalen Parameter der Klasse A. Welche Methode g() ausgeführt wird, ist abhängig von der übergebenden Referenz.

Ist meine Vermutung so korrekt? Ich möchte endlich richtig die Objektorientierung erlernen, ich habe solche Beispiele schon in einigen Fachbüchern gesehen. Daher denke ich, dass solches Wissen für ein grundlegendes Verständnis für die Objektorientierung darstellt.

MFG und danke !!
 
Zuletzt bearbeitet:
Warum ist es Möglich, der Methode f() ein Obejct der Klasse A und der Klasse B als formalen Parameter beim Aufruf mitzugeben
Wegen Polymorphie. Eine Object von B IST EIN Object von A. Und noch mehr.

welche Methode g() wird letztendlich ausgeführt.
Einfach ausprobieren:
Java:
class A{
	public void print(){
		System.out.println("a");
	}
}
class B extends A{
	@Override
	public void print(){
		System.out.println("b");
	}
}

public class C{
	public static void main(String[] args){
		new C().doIt(new A());
		new C().doIt(new B());
	}

	public void doIt(A a){
		a.print();
	}
}
Ausgabe:
a
b

Deine Vermutung ist korrekt.


Beim überschreiben von Methoden sollte man immer die Annotation
@Override
vor die Methode schreiben, dadurch benachrichtigt dich der Compiler falls diese Methode nichts überschreibt obwohl sie es ja eigentlich soll.
 
Zuletzt bearbeitet:
Richtig. B hat alles, was A auch hat (und eventuell etwas mehr), deshalb kann es auch überall verwendet werden, wo man A verwenden kann. Man sagt auch einfach, B "ist ein" (spezielles) A.

Um mal ein Beispiel zu bringen, wenn A ein Flugzeug ist, könnte B ein Wasserflugzeug sein. Jedes Flugzeug muss z.B. landen können (Methode g(), selbst wenn diese bei manchen Flugzeugtypen noch "spezialisiert" werden muss).

Ein einfaches Beispiel aus den Java-Bibliotheken wäre die Klasse Number, von der die Klassen Integer, Long, Double, Float usw. ableiten. Number ist abstrakt, d.h. es gibt in Wirklichkeit gar keine Objekte vom Typ Number. Trotzdem kann man Methoden schreiben, die den Typ Number als Parameter haben, nämlich dann, wenn es einem gerade egal ist, ob in Wahrheit ein Integer-Objekt, Double-Objekt usw. geliefert wird, sondern man mit den "allgemeineren" Eigenschaften von Number bereits zufrieden ist (und sich die Arbeit spart, für jeden Untertyp eine separate Variante der Methode zu schreiben)
 
So wie du die Methode g() in Klasse C aufrufst, müsste sie eigentlich in C definiert sein.
Wenn das nicht der Fall, wovon ich jetzt mal ausgehe, sollte das so aussehen:
Java:
public class C{
      public void f(A object){
           object.g();
      }
}
 
So wie du die Methode g() in Klasse C aufrufst, müsste sie eigentlich in C definiert sein.
Wenn das nicht der Fall, wovon ich jetzt mal ausgehe, sollte das so aussehen:
Java:
public class C{
      public void f(A object){
           object.g();
      }
}

Ja Du hast recht gehabt, ich habe es eben nochmal ausgetestet ! Danke für die Beteiligungen zu meiner Frage !!
 
Java:
public class C{
	public static void main(String[] args){
		new C().doIt(new A());
		new C().doIt(new B());
	}

	public void doIt(A a){
		a.print();
	}
}

Hallo nochmal !

Diese Schreibweise...

Java:
new C().doIt(new A());

...ist mir bisher unbekannt gewesen. Bisher waren mir nur solche Codebsp. geläufig:

Java:
C object = new C();

object.doIt(new A());

Meine Frage:

Java:
new C().doIt(new A());
new C().doIt(new B());

Werden hier zwei seperate Objekte / Instanzen der Klasse C erzeugt? Oder wird das erste Objekt (also aus der ersten Codezeile) mit dem Objekt aus der zweite Codezeile überschrieben!?

Wenn es zwei verschiedene Objekte sind, dann werden diese ja erst vom Garbage Collector gelöscht, wenn sie nciht mehr referenziert werden (also mit "= null" bspw.)
 
es sind zwei,

> Oder wird das erste Objekt (also aus der ersten Codezeile) mit dem Objekt aus der zweite Codezeile überschrieben!?

überschreiben bedeutet doch auch zwei (unterschiedliche) Objekte?

> wenn sie nciht mehr referenziert werden (also mit "= null" bspw.)

da keine Variable belegt wird, ist auch nichts mit null zu überschreiben, direkt nach dem Kommando können sie gelöscht werden,
falls die Konstruktoren und Methodenaufrufe die Objekte nicht irgendwo speichern (z.B. in statischen Listen)
 
Meinst Du damit so etwas wie eine ArrayList ?
Nicht direkt. Das hier wäre ein beispiel dafür:

Java:
class A{
	
	private static List <A> instances = new ArrayList <A> ();
	
	public A(){
		instances.add(this);
	}
}
Jedes Object, das du von A erstellst, wird in der statischen List "instances" referenziert und deswegen nie wieder vom Garbage Collector weggeräumt, solange du instances nicht irgendwie leerst.
 
Hallo !

Danke für Deinen Post ! Also mit dem Objekt "List" bin ich noch nie in Berührung gekommen, kannst Du mir vielleicht kurz erklären, worum es sich dabei handelt?
 
Zuletzt bearbeitet:
@Leroy
reg dich doch net wegen so einem "Tippfehler" auf, das Problem des TO war das OOP was dahinter steckt und mit Sicherheit nicht der Compilerfehler.
 
Hallo !

Ich hab nochmal ne Frage: Wann macht es konkret Sinn ein Objekt nicht über eine Referenzvariable zu erzeugen, also so:

Java:
Klasse1 object = new Klasse1();

und hier die Alternative:

Java:
new Klasse1();

Das macht doch nur Sinn, wenn ich mein Objekt nicht über eine Referenzvariable zur Laufzeit ansprechen muss oder?!
 
ja, bzw. eher andersum:
nur dann in einer Variablen speichern, wenn das auch notwendig ist
(obwohl es der Normalfall ist)

außerdem gibts noch den relativ häufigen Fall, dass das erzeugte Objekt direkt an eine Methode übergeben wird:
button.addActionListener(new ActionListener());
 
Java:
button.addActionListener(new ActionListener());

Also hier kann ich das gewünschte Objekt erzeugen und gleichzeitig direkt an eine Methode weitergeben. Es wäre aber auch folgende Konstellation möglich:

Java:
ActionListener action = new ActionListener();

button.addActionListener(action);

Ob das sinnvoll ist, sei jetzt mal egal. Mit geht es nur um die grundlegende Funktionalität von Java. Ich will ja mal nen Guru werden ! :toll:😉
 
Wenn die Klasse "Student" von der Klasse "Person" erbt, dann ist ein "Student" eine "Person". Und noch mehr: "Student" hat z.B. zusätzlich eine Matrikelnummer.
 
Wenn die Klasse "Student" von der Klasse "Person" erbt, dann ist ein "Student" eine "Person". Und noch mehr: "Student" hat z.B. zusätzlich eine Matrikelnummer.

Gehen mir mla davon aus, dass die Klasse Person ein Attribut hat, welches mit private deklariert wurde. Außerdem beinhaltet sie noch eine Get- und eine Setmethode für dieses Attribut (beide Methoden sind public)

Nun erweitert die Klasse Student die Klasse Person. Die Klasse Student erbt nun die beiden Methoden.

Stimmt es, dass die Klasse Student nur die public-Methode erbt, aber nicht das Attribut!? Sie kann nur über die beiden Methoden auf dieses Feld zugreifen? Werden nun zur Laufzeit ein Objekt der Klasse Person eines der Klasse Student erzeugt, existieren dann zwei verschiedene private Attribute !?
 
Attribute sind in der Regel "private" und sind ausserhalb der Klasse nur über Zugriffsmethoden erreichbar (Prinzip des Information Hiding). Wenn wir ein Objekt der Klasse Person erzeugen und eines der Klasse Student, dann sind das immer zwei getrennte Objekte mit jeweils eigenen, unabhängigen Attributen, egal wo die beiden Objekte erzeugt werden.
Da ein Objekt der Klasse Student auch eine Person ist, hat es natürlich auch die Schnittstellen der Klasse Person, wie z.B. getNachname/setNachname und getVorname/setVorname.
 
Zuletzt bearbeitet:
wenn du ein Object von Student erzeugst, werden natürlich auch alle privaten Variablen die in der Klasse Person stehen, erzeugt, initialisiert usw...
Der einzige Unterschied zu nicht-privaten Membervariablen ist, das man in der Sohn-Klasse nicht direkt diese Variablen ansprechen kann.
 
Naja Du kannst die Privateattribute, egal ob nun in vater- oder Sohnklasse, nur über die entsprechenden Set- und Getmethoden ansprechen.
 
man kann nur in der Klasse in der private Variablen/Methoden deklariert sind diese direkt ansprechen.

Also brauch die Vaterklasse ihre eigenen getter/setter nicht benutzen, sie kann ihre eigenen privaten Membervariablen direkt ansprechen
 
Also brauch die Vaterklasse ihre eigenen getter/setter nicht benutzen, sie kann ihre eigenen privaten Membervariablen direkt ansprechen

Aber verstößt dies nicht gegen einen guten objektorientierten Programmierstil. Ein Beispiel:

Java:
public class Vater {

     private String attribut1

     public String getAtt1(){

              return attribut1;

     }

     public void setAtt1(String attribut1){

              this.attribut1 = attribut1;

     }

Java:
public class Anwendung{

      public static void main(String[] args){

            Vater refV = new Vater();

             refV.attribut1 = "Test"    // So funktioniert das !?

      }     

}

Ist das so korrekt, wie ich es in der main-Methode gemacht habe ?
 
Nein. Das ist auch überhaupt nicht das was ich gesagt habe. Jede Klasse kann IHRE EIGENEN privaten Membervariablen immer sehen.
In deinem Beispiel versuchst du von einer anderen Klasse aus drauf zuzugreifen..
 
Aber verstößt dies nicht gegen einen guten objektorientierten Programmierstil. Ein Beispiel:
Java:
public class Vater {
     private String attribut1
     public String getAtt1(){
              return attribut1;
     }
     public void setAtt1(String attribut1){
              this.attribut1 = attribut1;
     }
Java:
public class Anwendung{
      public static void main(String[] args){
            Vater refV = new Vater();
             refV.attribut1 = "Test"    // So funktioniert das !?
      }     
}
Ist das so korrekt, wie ich es in der main-Methode gemacht habe ?
In Java ist der Zugriffsschutz klassenbezogen und nicht objektbezogen implementiert. Hier:
Java:
refV.attribut1 = "Test"    // So funktioniert das !?
enthält "refV" die Referenz auf ein Objekt. Obschon es ein Objekt der Klasse "Vater" ist, hat es keinen Zugriff auf die private "Vater"-Variable "attribut1", weil sich "refV" innerhalb einer anderen Klasse befindet, nämlich der Klasse "Anwendung".
 
Hallo nochmal !

Ich habe nochmal eine Frage zur Vererbung, besser gesagt zur Instanziierung von Klassen. Hier der Code:

Java:
public class Vater{

      //hier steht irgendwas

}


Java:
public class Sohn extends Vater{

     //hier steht irgendwas

}


Meine Frage:

Warum funktioniert der folgende Code:

Java:
public static void main(String[] args){

    Vater refV = new Sohn();

}

und dieser nicht:

Java:
public static void main(String[] args){

    Sohn refV = new Vater();

}
 
Weil "Sohn" auch vom Typ "Vater" ist, aber "Vater" nicht vom Typ "Sohn".

"A extends B" bedeutet "A ist ein B".
 
Ok danke für die Erklärung ! Ich bin letztens beim Thema Entwurfsmuster über die folgende Definition gestolpert:

...Klassen können polymorph gesetzt werden...

Ist es genau das, was ich hier von euch wissen wollte, oder versteht man darunter etwas anderes !?

Viele Grüße
Dennis
 
Polymorphie bedeutet Vielgestaltigkeit. Eine Polymorphie von Objekten gibt es nur bei Vererbungshierarchien. An die Stelle eines Objektes in einem Programm kann stets auch ein Objekt einer abgeleiteten Klasse treten. Der Grund dafür ist, dass ein Objekt einer abgeleiteten Klasse polymorph ist. Es kann sich als Objekt der abgeleiteten Klasse, aber auch als ein Objekt irgendeiner Basisklasse verhalten. Ein Sohnobjekt ist sowohl vom Typ der eigenen Klasse als auch vom Typ jeder zugehörigen Basisklasse.
Polymorphie erlaubt es, gegebenenfalls große Mengen von generalisiertem Code für Basisklassen zu schreiben, der dann später von Objekten beliebiger abgeleiteter Klassen benutzt werden kann. Dabei ist natürlich beim Schreiben des Codes für die Basisklasse überhaupt nicht bekannt, welche Klassen zu späteren Zeitpunkten von der Basisklasse abgeleitet werden.
 
Perfekt, vielen Dank für die schöne Erläuterung !! Also programmiere ich nicht konkret auf irgendeine Implementierung hin, sondern programmiere eher auf den Supertypen hinaus? Ich glaube, dass macht auch Sinn, wenn mein Programm irgendwann mal erweitert werden soll.

Aber nochmal kurz anderes (ich denke danach bin ich euch genug auf die Nerven gegangen, aber eure Hilfsbereitschaft hilft mir sehr, die Sprache Java immer besser zu verstehen).

Wann genau macht es Sinn vor eine Methode oder einer Variable ein this. zu setzen? Wir das im Zweifel nicht automatisch vom Java-Compiler gemacht ?
 
Perfekt, vielen Dank für die schöne Erläuterung !! Also programmiere ich nicht konkret auf irgendeine Implementierung hin, sondern programmiere eher auf den Supertypen hinaus? Ich glaube, dass macht auch Sinn, wenn mein Programm irgendwann mal erweitert werden soll.

Das ganze ist furchtbar simpel: Man erhöht einfach die Flexibilität seines Codes.

Diese Methode ist nur für HashSets "geeignet":
Java:
public void printAll(HashSet<String> set) {
   for(String s: set) {
      System.out.println(s); 
   }
}
Aber wir nutzen ja gar keine speziellen Eigenschaften von HashSet, warum sollten wir uns freiwillig darauf beschränken? Die Methode würde ja genauso für ein TreeSet funktionieren, also nehmen wir doch gleich das Interface Set:
Java:
public void printAll(Set<String> set) {
   for(String s: set) {
      System.out.println(s); 
   }
}
Moment, was ist, wenn jetzt eine Liste kommt? Ist die Methode dann immer noch sinnvoll? Sicher. Warum verallgemeinern wir dann nicht weiter?
Java:
public void printAll(Collection<String> collection) {
   for(String s: collection) {
      System.out.println(s); 
   }
}
Mit einer minimalen Änderung sind wir von einer (ohne guten Grund) hochspezialisierten Methode zu einer viel allgemeineren gelangt, die für alle möglichen Arten von Kollektionen (selbst welchen, die zum Implementierungszeitpunkt noch gar nicht geschrieben wurden) arbeitet.

Aber nochmal kurz anderes (ich denke danach bin ich euch genug auf die Nerven gegangen, aber eure Hilfsbereitschaft hilft mir sehr, die Sprache Java immer besser zu verstehen).

Wann genau macht es Sinn vor eine Methode oder einer Variable ein this. zu setzen? Wir das im Zweifel nicht automatisch vom Java-Compiler gemacht ?

Oft muss man es nicht machen, aber manchmal wird die Instanz-Variable von einer lokalen Variable (bzw. einem Parameter) "verdeckt":
Java:
class Foo {
   int bar;
   public void setBar(int bar) {
      //jetzt verweist "bar" auf den Parameter und nicht auf die Instanz-Variable
      //deshalb braucht man jetzt "this", wenn man die Instanz-Variable meint
      this.bar = bar;
   }
}
 
Es ist nichts anderes, sondern nur eine Referenz auf das Objekt, in dem du dich gerade "befindest". Du musst es ja irgendwie ansprechen können, etwa hier:

Java:
class Foo {
   public Foo copy() {
       //Foo ist unveränderlich, wir brauchen also nicht unbedingt eine Kopie zu machen, 
       //sondern können ruhig "das Objekt selbst" zurückgeben.
       //Aber wie nennen wir jetzt "das Objekt selbst"?
       return this;  
   }
}
 
Obiges Beispiel mit "HashSet" weicht insofern vom Thema ab, als es zusätzlich das Konzept der Schnittstellen einführt und dieses mit dem Konzept der Polymorphie verbindet (Polymorphie wird ursprünglich nur auf Vererbung bezogen). Der Zugriff auf verdeckte Instanzvariablen der Vaterklasse geht mit ((Vater)this).variablenName (oder einfach mit super.variablenName). Bei anonymen Klassen ist manchmal der Konstrukt KlassenName.this.variablenName erfordert, um auf eine Variable der umschliessenden Klasse zugreifen zu können.
 
Salve Javagemeinde !

Ich muss nochmal etwas von euch wissen. Es geht um das dynamische- und das statische Binden. Was das genau ist, brauchen wir nicht zu erörtern ! Ein prof. von mir behauptet in seinem Skript, dass es manchmal besser sein, nicht alle Methoden dynamisch zu binden.

Aber warum ist das so? Das kann ich mir mit meinen Grundkenntnissen in Java irgendwie nicht so richtig erklären...

MFG
 
Die Entscheidung, ob eine Methode dynamisch gebunden, d.h. polymorph, sein soll oder nicht, hat nix mit Java zu tun, das hängt allein von der Anwendung ab. Die "toString"-Methode sollte stets polymorph sein, damit man erkennt, welche Klasse mit dem String gemeint ist. Wenn die ererbte Methode den Ansprüchen der Sohnklasse genügt, dann braucht man sie nicht zu überschreiben. Bei "getClass" z.B. wäre es sinnlos.
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben