Frage zu Vererbung

Razernut

Neues Mitglied
Liebe Javakenner ;).
Ich bin Informatikstudent im ersten Semester und bearbeite derzeit eine Hausaufgabe zum Thema Vererbung, bei der es darum geht zu beschreiben, was die Ausführung der main-Methode von Klasse C bewirkt.
Als erstes einmal führe ich die Klassen A,B und C an:
Java:
public class A 
{
    private int a;
    
    public A(int a)
    {
        this.a = a;
    }

    public int getA()
    {
        return this.a;
    }

    public int add(A a)
    {
        return this.a + a.getA();
    }

    public int m()
    {
        return 1;
    }

    public int n()
    {
        return this.m();
    }

    public String toString()
    {
        return "Ich bin ein A.";
    }
}
Java:
public class B extends A 
{
    private int a;
    
    public B(int a)
    {
        super(a);
    }

    public int getA()
    {
        return this.a;
    }

    public int add(B b)
    {
        return this.getA() + b.getA();
    }

    public int m()
    {
        return 2;
    }

    public String toString()
    {
        return "Ich bin ein B.";
    }
}
Java:
public class C 
{
    public static String print(A a)
    {
        return "Parameter A: " + a.toString();
    }

    public static String print(B b)
    {
        return "Parameter B: " + b.toString();
    }

    public static void main(String[] args) 
    {
        A o1 = new A(2);
        B o2 = new B(3);
        
        //Frage #1
        A o3 = new B(4);

        System.out.println(o1.m() + o2.m());
        System.out.println(o2.m() + o3.m());
        
        System.out.println(o2.n());

        System.out.println(print(o1));
        System.out.println(print(o2));
        System.out.println(print(o3));

        System.out.println(o1.add(o1));
        System.out.println(o1.add(o2));
        
        //Problem #1
        System.out.println(o2.add(o3));
        
        System.out.println(o2.add(o2));
    }
}

Ich habe nun eine Verständnisfrage und ein Problem, hinter das ich einfach nicht komme.
Beide befinden sich in Klasse C und sind mit Kommentaren markiert.

Nun zu Frage #1:
Die Klasse B ist ja eine Erweiterung der Klasse A. Warum kann ich der Variable o3, die meiner Ansicht nach ja von Typ A ist einen "Wert" bzw. ein Objekt der Klasse B zuweisen? Geht dies, da B eine Erweiterung der Klasse darstellt? Denn andersrum scheint es nicht zu gehen einer Variable von Typ B ein Objekt der Klasse A zuzuweisen.

Problem #1:
Ich war der festen Überzeugung, dass hier 0 herauskommen müsste.
Hier eine Formulierung, von was ich denke dass pasiert:
Es wird hier eine Zeile auf der Konsole ausgegeben die dem Wert entspricht, den die Methode add des Objekts o2 (Welches von Klasse B ist) returned. Die Methode add von o2 wiederum ruft die Methode getA der Klasse B auf, welche aber meiner Meinung nach dann nicht 3 zurückgeben dürfte, sondern 0. Denn es existieren ja 2 verschiedene Variablen a in der Klasse B. Die eine, die von A geerbt wird und die zweite, welche ganz oben in der Klasse deklariert wird. Und durch den Konstruktor von B sollte eigentlich ersterer der Wert von 3 zugewiesen werden. Somit sollte this.a die Variable sein, derer Wert immer noch 0 ist. Bei o3 sollte durch o3.getA() meiner Meinung nach auch 0 zurückkommen, genau wie bei o2 aus selbigen Gründen.
Warum also erhalte ich hier am Schluss auf der Konsole das Ergebnis 3?

Ich hoffe ich konnte meine Fragen übersichtlich darstellen und bedanke mich schon einmal im Voraus für die Mühe!

MfG

Razernut
 
N

nillehammer

Gast
Nun zu Frage #1:
Die Klasse B ist ja eine Erweiterung der Klasse A. Warum kann ich der Variable o3, die meiner Ansicht nach ja von Typ A ist einen "Wert" bzw. ein Objekt der Klasse B zuweisen? Geht dies, da B eine Erweiterung der Klasse darstellt? Denn andersrum scheint es nicht zu gehen einer Variable von Typ B ein Objekt der Klasse A zuzuweisen.
Korrekt, Vererbung ist eine "ist ein"-Beziehung. Der Subtyp ist also immer ein gültiger Ersatz für den Supertypen. Wenn ich z.B. sage: Kauf Gemüse ein.(der Supertyp) und Du bringst mir Gurken (der Subtyp) mit. So hast Du die Anforderung erfüllt. Gurke ist ein valider Ersatz für Gemüse. Wenn ich aber sage bring mir Gurken mit, dann musst du mir genau Gurken mitbringen und nicht (irgend ein) Gemüse.

Die Frage wieso 3? Hab ich grad keine Lust nachzuvollziehen. Bau einfach in alle Methoden System.out.printlns ein oder jage Dein Programm durch den Debug-Modus. Dann siehst du ganz genau was, wann, wonach aufgerufen wird. Eine Sache, die man gerne vergisst ist, dass Konstruktoren von Subklassen als aller erstes immer einen Super-Konstruktor aufrufen. Wenn das nicht explizit als
Code:
super(...)
im Code auftaucht ist dies der argumentlose Defaultkonstruktor. Weil's eben oft nicht explizit im Code steht, wird es bei der Ablaufanalyse gerne übersehen.
 
Zuletzt bearbeitet von einem Moderator:

Olli_M

Mitglied
this.a ist ja auch 0, und zwar in Klasse B. Die add-Methode wird in Klasse A aufgerufen.
Dort steht this.a, welches 3 ist. a.getA() ist 0. 3 + 0 = 3

Durch System.out.println sieht man das recht schnell.
Die add-Methode in Klasse B wird in dem Beispiel nicht aufgerufen.
 

Neue Themen


Oben