# Statischer und Dynamischer Typ



## ocsme (1. Feb 2019)

Guten Tag,
hab ein Problem mit dem Statischen und Dynamischen Typ bei der Vererbung.
Hier mal ein Code Beispiel:

```
public class A{
public static int x=1;
    public A() {
        x+=3;
    }
    public int f(int y) {
        return y+x;
    }
    public int f(double y) {
        x=0;
        return (int)y;
    }   
}

public class B extends A {
    public int y=3;
    public B(int x) {
        super();
        y+=x;
    }
    public int f(double x) {
        y+=1;
        return (int)x*y;
    }
       
}
```

Nun soll man schauen was bei folgendem raus kommt:

```
A a = new B(2);
    System.out.println(A.x+" "+((B)a).y);
    int z=a.f(4.5);
    System.out.println(((B)a).y+" "+z+" "+A.x);
    B b = (B) a;
    z = b.f(5);
    System.out.println(b.y+" "+z+" "+A.x);
```

Dachte eigentlich ich hätte es verstanden doch nichts habe ich! 

1. Wieso muss a so gecastet werden ((B)a)? Der Statische Typ ist doch A und der Dynamische Typ ist B damit schaut er doch in der Variable a erst mal in der Classe von B nach oder etwa nicht? dort sollte er das Datenelement finden.
2. a.f(4.5) sollte er auch in der Classe von B nachschauen da das ja der Dynamsche Typ ist und die Methode dort gefunden wird.
3. B b = (B)a was passiert hier genau? Denn ich hätte gesagt das wäre equivalent zu B b = new B(2); also von oben A a = new B (2); ich presse den Dynamischen Typ B in den Statischen Typ B also B = B!!! scheint aber auch Falsch zu sein den eclipse zeigt mir dann auch Methoden von A an 
4. Welche Funktion wird dann bei z = b.f(5) aufgerufen das sollte sich mit 3. erklären lassen 

Die 4 Fragen hätte ich zu dieser Aufgabe denn ich verstehe jetzt nichts mehr 

LG


----------



## httpdigest (1. Feb 2019)

1.: Der statische Typ der Variablen `a` ist `A` und der dynamische Typ des Objektes, welches in der Variablen `a` gespeichert ist, ist `B`. Aber bei Feld- bzw. Instanzvariablenzugriffen findet kein dynamic Dispatch statt - nur bei Methodenaufrufen! Das heißt, es muss zur Compilezeit feststehen, welches `a` aus welcher Klasse du da ganz genau meinst. Und, wenn du eben auf das `a` von `B` statt von `A` zugreifen willst, dann musst du `B` als statischen Typ nutzen.
2.: Korrekt. Hier wird er zur Laufzeit die überschriebene f(double) Methode in `B` aufrufen.
3.: Hier passiert genau dasselbe, was auch bei `((B)a)` passierte. Nur, dass hier der statische Typ des Ausdrucks auch nochmal für eine Variable verwendet wird, der `a` zugewiesen wird. Das heißt, jetzt gibt es eine Variable, deren statischer Typ `B` ist und die dasselbe Objekt enthält, das auch die Variable `a` vorher enthielt. Da wird aber kein Konstruktor aufgerufen, also es wird hier allein durch den bloßen Cast kein neues `B` Objekt erzeugt! Es wird nur der Compilezeittyp festgesetzt/geändert auf `B`.
4.: 3. erklärt das nicht. Es wird hier die nicht-überschriebene Überladung f(int) der Klasse A aufgerufen.


----------



## ocsme (1. Feb 2019)

Ich danke dir aber ich verstehe es trozdem immer noch nicht so richtig!
Werde mir das morgen erneut anschauen

LG

PS: wieso kann ich wenn ich ein Getter int getY(){return y;} in die Klasse B schreibe ihn mit a.getY() nicht aufrufen?


----------



## httpdigest (1. Feb 2019)

Merk' dir einfach erstmal folgendes: *Ausdrücke* haben immer nur *statische Typen*. *Objekte* (die durch die Auswertung von Ausdrücken entstehen) haben *dynamische Typen*.


ocsme hat gesagt.:


> wieso kann ich wenn ich ein Getter int getY(){return y;} in die Klasse B schreibe ihn mit a.getY() nicht aufrufen?


Alle Ausdrücke müssen einen klaren/definierten _statischen_ Typen haben. Da es in der Klasse `A` (welches ja der _statische_ Typ von `a` ist) keine solche Methode `getY()` gibt, weiß der Compiler nicht, was er jetzt machen soll und von welchem _statischen_ Typen denn das Ergebnis von `getY()` wäre. Das heißt, selbst bei normalerweise dynamic dispatch'ten Methodenaufrufen muss _immer_ trotzdem der _statische_ Typ bekannt sein.


----------



## ocsme (1. Feb 2019)

Dank dir 
Jetzt ist mir das ganze erneut Klarer geworden. Werde mich morgen aber wieder hin setzen und das ganze wieder nachlesen.
Bis jetzt hatte ich nur Übungen gemacht in denen Methoden von Vererbten Klassen aufgerufen wurden da hatte ich solche Probleme nicht.
Nochmals Danke httpdigest. Falls ich morgen weiter Fragen habe melde mich erneut 

LG


----------



## Meniskusschaden (1. Feb 2019)

ocsme hat gesagt.:


> aber ich verstehe es trozdem immer noch nicht so richtig!


Man kann es sich vielleicht leichter vorstellen, wenn das Objekt nicht direkt rechts vom Gleichheitszeichen mit new erzeugt wird, sondern von irgendwo anders geliefert wird. Dann wird deutlicher, dass der Compiler nur wissen kann, dass es zwar ein A ist, aber nicht notwendigerweise gleichzeitig ein B.

In folgendem Beispiel ist klar, dass der Compiler mb() und mc() nicht aufrufen kann:

```
import java.util.Random;

public class Main {

    public static void main(String[] args) {
        A a = instantiateSubtypeOfA();
        a.ma();
    //  a.mb();
    //  a.mc();
    }

    private static A instantiateSubtypeOfA() {
        return new Random().nextBoolean() ? new B() : new C();
    }
}

class A {
    public void ma() {}
}

class B extends A {
    public void mb() {}
}

class C extends A {
    public void mc() {}
}
```


----------



## ocsme (4. Feb 2019)

Ich danke euch nochmals viel mal 
Denke das ich es nun soweit verstanden habe.
Hab mal wieder eine kleine Datenstruktur geschrieben über Luftfahrzeuge 
Dort hat man eine Aufgabe man soll eine Methode schreiben, die Methode erhält ein Array von Luftfahrzeugen als Paramter übergeben, daraus ermittelt man die Anzahl der Düsenflugzeuge im Array bei denen die Anzahl an Besatzungsmitgliedern genau eines ist und die zugleich mit Überschallgeschwindigkeit fliegen.

Das Düsenflugzeug ist abgeleitet von Luftfahrzeug. Diese Klasse habe ich so geschrieben:

```
public class Luftfahrzeug {

    protected int besatzungsMittglied;
    protected String name;
   
    public int getBesatzungsMittglied() {
        return besatzungsMittglied;
    }
   
    public void setbesatzungsMittglied(int besatzungsMittglied) {
        this.besatzungsMittglied=besatzungsMittglied;
    }
   
    public String toString() {
        return name;
    }
}
```

das Düsenflugzeug sieht wie folgt aus:

```
public class Duesenflugzeug extends Luftfahrzeug implements SchwererAlsLuft{
   
    private boolean ueberschall;
   
    Duesenflugzeug() {
        name="Duesenflugzeug";
        int k=(int)(Math.random()*2+1);
        if(k==1) {
            setbesatzungsMittglied(k);
            int a=(int)(Math.random()*2+1);
            ueberschall=(a==1)?true:false;
        }
            else {
                setbesatzungsMittglied((int)(Math.random()*10+1));
                int a=(int)(Math.random()*2+1);
                ueberschall=(a==1)?true:false;
            }
    }
    public boolean getUeberschall() {
        return ueberschall;
    }
   
    public void setUeberschall(boolean ueberschall) {
        this.ueberschall=ueberschall;
    }

    public void lenkbar(double winkel) {
       
    }
}
```

Nun habe ich in der main ein Array gefühlt mit Flugzeugen. Danach suche ich wie oben beschrieben die Düsenflugzeuge raus. Ich überprüfe mit instanceof erst einmal ob ich aus Luftfahrzeug ein Düsenflugzeug gefunden habe danach kann ich aus dem Statischen Typ Luftfahrzeug casten und der Compiler sieht die Methoden von Düsenflugzeug 


```
Luftfahrzeug[] liste = new Luftfahrzeug[10];
        befuehllenZufall(liste);
       
       
        for(int i=0;i<liste.length;i++) {
            if(liste[i] instanceof Duesenflugzeug) {
                System.out.println(((Duesenflugzeug)liste[i]).getUeberschall()+" "+((Duesenflugzeug)liste[i]).getBesatzungsMittglied());

            }
```

Ich weiß das das ganze unvollständig ist und der gleichen es geht mir nur darum das ich verstehe wie es geht mit der Vererbung 
Kann nur hoffen das ich es nun soweit richtig verstanden habe 

LG


----------

