OOP

Hallo,

1)
Warum kann man von einer statischen Variablen ein neues Objekt erzeugen?
Und was ist der Unterschied zwischen diesen beiden Codebeispielen?

Java:
// Code-Snippet 1
static Lebensmittel aktuellesLebensmittel;
aktuellesLebensmittel = new Lebensmittel();

// Code-Snippet 2
Lebensmittel aktuellesLebensmittel;
aktuellesLebensmittel = new Lebensmittel();

2)
Warum wird hier die toString() Methode von der Klasse Brot aufgerufen und nicht von Lebensmittel? Mit der Variablen l kann man doch nicht auf Methoden der Klasse Brot zugreifen, da der deklarierte Typ festlegt, auf was ich Zugriff habe.
Die Klasse Brot erbt von Lebensmittel.

Java:
Lebensmittel l = new Brot("Weizenbrot", 265);
l.toString();
 

Flown

Administrator
Mitarbeiter
1. Diese Frage ist wirr. Code-Snippet 1 ist kein valider Code (Tutorial)
- Der Unterschied: Bei dem Ersten - wenn es valider Code wäre - würde eine Klassenvariable initialisieren. Bei dem zweiten Code wird eine Objektvariable initialisiert.

2. Stichwort lautet hier dynamic dispatching und ist eines der Hauptgründe für Vererbung.
 
@Flown
Dieser Code compiliert.
Zu 1)

Java:
public class Lebensmittel {
   
    protected String name;
    protected int kcal;
   
    Lebensmittel(String name, int kcal){
        this.name=name;
        this.kcal=kcal;
    }
   
    @Override
    public String toString() {
        return "Name: " + name + "\tkcal: " + kcal;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getKcal() {
        return kcal;
    }

    public void setKcal(int kcal) {
        this.kcal = kcal;
    }

}


public class Brot extends Lebensmittel{
   
    protected int preis;
   
    Brot(String name, int kcal, int preis){
        super(name,kcal);
        this.preis=preis;
    }
   
    @Override
    public String toString() {
        return super.toString() + "\tPreis: " + preis;
    }

    public int getPreis() {
        return preis;
    }

    public void setPreis(int preis) {
        this.preis = preis;
    }

}



public class LebensmittelDemo {
   
    static Lebensmittel aktuellesLebensmittel;
   
    public static void main(String[] args) {
       
        aktuellesLebensmittel = new Lebensmittel("Apfel", 200);
        aktuellesLebensmittel.setKcal(400);
    }

}

Mir ist noch nicht klar, was das static vor der Variablen machen soll bzw. warum man sowas static macht?


Zu 2)
Also wird die toString Methode aus der Klasse Brot aufgerufen, weil das Objekt vom Typ Brot ist?
Ich habe aber gelernt, dass der deklarierte Typ festlegt, auf was ich Zugriff habe. Was stimmt jetzt?
 

Harry Kane

Top Contributor
Also wird die toString Methode aus der Klasse Brot aufgerufen, weil das Objekt vom Typ Brot ist?
Ich habe aber gelernt, dass der deklarierte Typ festlegt, auf was ich Zugriff habe. Was stimmt jetzt?
Beides. Der deklarierte Typ bestimmt die Methoden, die zur compile time aufrufbar sind. Der Typ zur runtime bestimmt, welche Methode tatsächlich aufgrufen wird.
 

Meniskusschaden

Top Contributor
Mir ist noch nicht klar, was das static vor der Variablen machen soll bzw. warum man sowas static macht?
Wenn sie als Klassenvariable deklariert ist (mit static) existiert genau ein Exemplar der Variablen, egal wieviele Objekte der Klasse gerade existieren (also auch falls gar keins existiert).
Wenn sie als Objektvariable deklariert ist (ohne static) existiert pro Objekt ein eigenes Exemplar der Variablen. Folgendes Testprogramm
Java:
public class A {
    private String name;
    private static int a1;
    private int a2;
  
    public A(String name) {
        this.name = name;
    }

    public A inc() {
        a1++;
        a2++;
        System.out.println(this);
        return this;
    }

    @Override
    public String toString() {
        return name + ": a1=" + a1 + ", a2=" + a2;
    }

    public static void main(String[] args) {
        new A("A").inc();
        new A("B").inc();
        new A("C").inc().inc().inc().inc();
        new A("D").inc();
    }
}
erzeugt diese Ausgabe:
Code:
A: a1=1, a2=1
B: a1=2, a2=1
C: a1=3, a2=1
C: a1=4, a2=2
C: a1=5, a2=3
C: a1=6, a2=4
D: a1=7, a2=1
 
@Meniskusschaden
Das heißt jedes Objekt teilt sich die statische Variable?
Bisher dachte ich statische Variablen beschreiben keine Interaktion mit Objekten einer Klasse?
Deswegen frage ich mich auch, warum es mit einer Klassenvariablen möglich ist den Konstruktor oder Methoden aufzurufen?
Bisher kannte ich nur das hier Klassenname.Klassenvariable oder Klassenname.Klassenmethode

@Harry Kane
Beides. Der deklarierte Typ bestimmt die Methoden, die zur compile time aufrufbar sind. Der Typ zur runtime bestimmt, welche Methode tatsächlich aufgrufen wird.

Das heißt zur Compilezeit hat man Zugriff auf die Methode der Klasse Lebensmittel und nicht auf die Methode in der Klasse Brot? Aber zur Runtime wird die Methode aus der Klasse Brot aufgerufen?
Und warum gibt es die Unterscheidung zwischen Compile und Runtime im Bezug auf den Methodenaufruf?
 

Flown

Administrator
Mitarbeiter
Das heißt jedes Objekt teilt sich die statische Variable?
Ja, du kannst es als globalen State der Klasse sehen.
Bisher dachte ich statische Variablen beschreiben keine Interaktion mit Objekten einer Klasse?
Können interagieren, da sie im Scope des Objekts sind.
Deswegen frage ich mich auch, warum es mit einer Klassenvariablen möglich ist den Konstruktor oder Methoden aufzurufen?
Umgekehrt du kannst eine Methode/Konstruktor mit einer Klassenvariable aufrufen nicht umgekehrt.
Bisher kannte ich nur das hier Klassenname.Klassenvariable oder Klassenname.Klassenmethode
So sollte das auch passieren, damit klar wird, dass das eine statische Variable oder Methode ist (sollte dir auch eine IDE so anzeigen).

Das heißt zur Compilezeit hat man Zugriff auf die Methode der Klasse Lebensmittel und nicht auf die Methode in der Klasse Brot?
Du garantierst mit der Variablendeklaration welche Methoden verfügbar sind. Wenn du Lebensmittel deklarierst, dann werden auch nur diese Methoden zur verfügung stehen. Wenn du aber eine Subklasse von Lebensmittel in die Variable packst, werden die Methoden der Subklasse verwendet (dynamische Bindung ;) - da die Methoden überschrieben werden können).
Aber zur Runtime wird die Methode aus der Klasse Brot aufgerufen?
Sozusagen
Und warum gibt es die Unterscheidung zwischen Compile und Runtime im Bezug auf den Methodenaufruf?
Gibt es nicht. Da du eine "is-a" Beziehung zwischen Lebenmittel und Brot hast besitzen beide die gleichen Methoden. Nur die Implementierung kann - ist auch in den meisten Fällen - unterschiedlich.
 

Neue Themen


Oben