# Aufgabe zu Unterklassen, Vererbung



## JavaIsTheBest (22. Feb 2016)

Hallo,
ich habe folgende Aufgabe, bei der ich im Moment nicht weiterkomme. Ich wäre über ein paar Ratschläge dankbar.


Spoiler: Klasse Account





```
// Klasse: Konto.
class Account {
  // Private Klassenvariable:
  // Naechste zu vergebende Kontonummer.
  private static int nextNumber = 1;

  // Private Objektvariablen:
  private final int number = nextNumber++;
                // Kontonummer (unveraenderlich).
  private String holder;    // Kontoinhaber.
  private int balance = 0;    // Kontostand.

  // Oeffentliche Konstruktoren: Konto mit Inhaber h, ggf.
  // Anfangsbetrag b und eindeutiger Nummer konstruieren.
  public Account (String h) {
    holder = h;
  }
  public Account (String h, int b) {
    this(h);            // Den anderen Konstruktor aufrufen.
    balance = b;
  }

  // Oeffentliche Objektmethoden:
  // Kontonummer/-inhaber/-stand abfragen.
  public int number () { return number; }
  public String holder () { return holder; }
  public int balance () { return balance; }

  // Oeffentliche Objektmethoden:
  // Betrag amount einzahlen/abheben/überweisen.
  public void deposit (int amount) {
    balance += amount;
  }
  public void withdraw (int amount) {
    balance -= amount;
  }
  public void transfer (int amount, Account that) {
    withdraw(amount);
    that.deposit(amount);
  }

  // Oeffentliche Klassenmethode:
  // Anzahl bereits erzeugter Konten abfragen.
  public static int numberOfAccounts () { return nextNumber - 1; }
}
```






Spoiler: Klasse LimitedAccount





```
// Unterklasse von Account: Limitiertes Konto.
class LimitedAccount extends Account {
  // Zusaetzliche Objektvariable:
  private int limit;        // Kreditlinie in Cent.

  // Konstruktoren:
  // Limitiertes Konto mit Inhaber h, ggf. Anfangsbetrag b,
  // Kreditlinie l und eindeutiger Nummer konstruieren.
  public LimitedAccount (String h, int b, int l) {
    super(h, b); // Konstruktor der Oberklasse Account aufrufen,
         // um deren Objektvariablen zu initialisieren.
    limit = l;     // Zusaetzliche Objektvariable limit initialisieren.
  }
  public LimitedAccount (String h, int l) {
    // Entweder:        // Oder:
    super(h);            // this(h, 0, l);
    limit = l;            //
  }

  // Zusaetzliche Objektmethode: Kreditlinie abfragen.
  public int limit () { return limit; }

  // Hilfsmethode: Kann Betrag amount abgezogen werden,
  // ohne die Kreditlinie zu ueberschreiten?
  private boolean check (int amount) {
    if (balance() - amount >= -limit) return true;
    System.out.println("Unzulaessige Kontoueberziehung!");
    return false;
  }

  // Ueberschreiben geerbter Objektmethoden:
  // Betrag amount abheben/ueberweisen.
  public void withdraw (int amount) {
    if (check(amount)) {
      // Ueberschriebene Methode aufrufen.
      super.withdraw(amount);
    }
  }
  public void transfer (int amount, Account that) {
    if (check(amount)) {
      // Ueberschriebene Methode aufrufen.
      super.transfer(amount, that);
    }
  }
}
```






Spoiler: Klasse ChargedAccount





```
public class ChargedAccount extends Account {
    private int count;
    public int charge=10;
   
    public ChargedAccount(String holder){
        super(holder);
    }
    public ChargedAccount(String holder, int balance){
        super(holder,balance);
    }
    public void deposit (int amount) {
        super.deposit(amount);
        count++;
    }
    public void withdraw (int amount) {
        super.withdraw(amount);
        count++;
    }
    public void charge(){
        // ......
    }
   
   
   

}
```


----------



## VfL_Freak (22. Feb 2016)

Moin,

Ratschläge für was ???
Du solltest Dein Problem schon wenigstens beschreiben !!

Gruß Klaus


----------



## JavaIsTheBest (22. Feb 2016)

Ich frage mich, ob mein bisheriger Code in der Klasse ChargedAccount richtig ist und ob ihr mir Hinweise zur Implementierung der Methode charge geben könnt.
Klasse Account und LimitedAccount waren gegeben.


----------



## Jardcore (22. Feb 2016)

Da es eine Klassenvariable sein soll muss sie in der Form *static "*final" deklariert werden.
In welcher Einheit ist der Kontostand? Cent? 


```
private static final int CHARGE = 10;

    public void charge() {
        count = 0;
        balance -= CHARGE;
    }
```

EDIT: zur Begriffserklärung ohne *static *ist es eine Instanzvariable und ohne *final *könnte sie noch veränder werden. Mit static final beschreibt man in Java Konstanten.


----------



## JavaIsTheBest (22. Feb 2016)

Woher kommt die Variable balance her?
Und muss es nicht so heißen?    balance-=CHARGE*count;


----------



## Jardcore (22. Feb 2016)

JavaIsTheBest hat gesagt.:


> Woher kommt die Variable balance her?


Kommt aus der Account Klasse (privateint balance =0;   // Kontostand.)
Und ja kann sein das man noch *count rechnen muss.


----------



## JavaIsTheBest (22. Feb 2016)

balance ist aber private. Wie soll das gehen?


----------



## Joose (22. Feb 2016)

Indem du die Sichtbarkeit änderst 
http://openbook.rheinwerk-verlag.de/javainsel9/javainsel_05_002.htm


----------



## JavaIsTheBest (22. Feb 2016)

Die Klasse Account ist vorgegeben und daran sollte ich eigentlich nichts ändern.


----------



## Meniskusschaden (22. Feb 2016)

JavaIsTheBest hat gesagt.:


> balance ist aber private. Wie soll das gehen?


Du mußt dir mal ansehen, welche Methoden du in der Klasse Account zur Verfügung hast.


----------



## Jardcore (22. Feb 2016)

```
public void charge(){
        withdraw(CHARGE * count);
        count = 0;
   }
```

Btw: du solltest deinem Lehrer mal sagen das Java Camel Case benutzt... das heißt withDraw(..);
Und Getter beginnen normalerweise auch mit einem get ... deswegen ja Getter XD

Muss gestehen hab das auch übersehen, dachte balance wurde public deklariert... aber das war ja der komische Getter^^

Edit:
Ich schätze mal die eigentliche Aufgabe ist hier zu verstehen wie was von wem warum auch immer irgendwas erbt und wie man trotzdem auch private Attribute zugreift. Und weniger die Aufgaben zu lösen^^


----------



## Meniskusschaden (22. Feb 2016)

Jardcore hat gesagt.:


> Btw: du solltest deinem Lehrer mal sagen das Java Camel Case benutzt... das heißt withDraw(..);
> Und Getter beginnen normalerweise auch mit einem get ... deswegen ja Getter XD


Also withdraw würde ich auch komplett klein schreiben. Ist doch eigentlich kein zusammengesetztes Verb. Ausserdem ist withdraw meines Erachtens auch kein Setter (nehme an, du meintest nicht Getter), denn die Zuweisung erfolgt ja mit -=.


----------



## Jardcore (22. Feb 2016)

Meine Englischkenntnisse waren da wohl nichtso gut  
withdraw = abheben

Ich meinte den getter getBalance() bzw. balance()


----------



## Meniskusschaden (22. Feb 2016)

Jardcore hat gesagt.:


> Ich meinte den getter getBalance() bzw. balance()


Den habe ich übersehen. Dann stimme ich dir zu.


----------



## JavaIsTheBest (22. Feb 2016)

Der Compiler gibt eine Fehlermeldung aus, weil die linke Seite keine Variable ist, aber es muss doch beim Aufruf der Methode charge der Kontostand geändert werden.



Spoiler: ChargedAccount





```
public class ChargedAccount extends Account {
    private int count;
    private static int charge=10;
   
    public ChargedAccount(String holder){  // Konstruktor von der Oberklasse erben
        super(holder);
    }
    public ChargedAccount(String holder, int balance){
        super(holder,balance);
    }
    public void deposit (int amount) {  //Methoden von der Oberklasse überschreiben
        super.deposit(amount);
        count++;
    }
    public void withdraw (int amount) {
        super.withdraw(amount);
        count++;
    }
    public void charge(){
        super.balance()-=charge*count;
        count=0;
    }
}
```


----------



## Meniskusschaden (22. Feb 2016)

super.balance() ist eine Methode. Der kannst du nichts zuweisen. Du musst sie mit den geeigneten Parametern aufrufen. Die Methode berechnet dann die Klassenvariable balance neu. Wie sie das berechnet, siehst du in der Klasse Account.


----------



## JavaIsTheBest (23. Feb 2016)

Die Methode balance hat keine Parameter und liefert nur den Kontostand zurück. Sonst macht die Methode nichts.
Deswegen, weiß ich immer noch nicht, was ch anders machen muss.


----------



## Meniskusschaden (23. Feb 2016)

Stimmt, habe nicht aufgepasst. Du musst withdraw() benutzen. Hat jardcore bereits demonstriert.


----------



## JavaIsTheBest (23. Feb 2016)

Ich weiß nicht, ob das so stimmt.


```
public void charge(){
        super.withdraw(charge*count);
        count=0;
    }
```

Ich habe mr überlegt, für ein ChargedAccount müssen vom eigenen Konto bei einer Überweisung "charge*count Cent" abgezogen werden.
Mir stellt sich die Frage, hätte/sollte/musste ich lieber für diese Operation die transfer Methode verwenden?


----------



## Meniskusschaden (23. Feb 2016)

Ich glaube, die charge-Methode ist so richtig.



JavaIsTheBest hat gesagt.:


> Ich habe mr überlegt, für ein ChargedAccount müssen vom eigenen Konto bei einer Überweisung "charge*count Cent" abgezogen werden.
> Mir stellt sich die Frage, hätte/sollte/musste ich lieber für diese Operation die transfer Methode verwenden?


Fragst du jetzt, ob du mit der transfer-Methode die Gebühren abbuchen sollst oder ob du damit die Überweisung abwickeln sollst? Bin mir nicht sicher, ob ich die Frage richtig verstanden habe.
Für eine gebührenpflichtige Überweisung fallen aber nicht "charge*count Cent" an, sondern nur "charge Cent". Aber eben nicht sofort, sondern erst sobald für das Konto die Gebührenberechnung mittels charge-Methode erfolgt. Das heisst, zum Gebühren abbuchen ist die transfer-Methode nicht gedacht, sondern um eine Überweisung von einem Konto auf ein anderes zu buchen.


----------



## Jardcore (23. Feb 2016)

Will hier kurz anmerken, das ich mich mit der genauen Aufgabenstellung nicht beschäftigt habe.
Also ob CHARGE * count oder was auch immer. Wichtig ist nur wie du darauf zugreifen kannst und dafür sind ein paar Methoden im Account definiert. Welche Rechnung nun erforderlich ist, steht hoffentlich in der Aufgabenstellung


----------



## JavaIsTheBest (23. Feb 2016)

@Meniskusschaden
Die Gebühr für eine Überweisung beträgt 10 Cent. Wenn man 4 Überweisungen tätigt, dann beträgt die Gebühr 4*10=40  Cent.
Warum also nicht count*charge?
Oder könntest  du, mir die Aufgabenstellung erklären? Ich weiß nicht, ob der Gedankengang so richtig ist.


----------



## Meniskusschaden (23. Feb 2016)

Du hattest in Post #19 geschrieben, dass bei EINER Überweisung "count*charge Cent" abgezogen werden. Das wollte ich nur richtig stellen, denn bei EINER Überweisung sind es nur "charge Cent". In der Methode charge() sollen aber ALLE gebührenpflichtigen Buchungen belastet werden. Dort sind es deshalb "charge*count Cent".


----------



## JavaIsTheBest (23. Feb 2016)

Achso ok 
Bks jetzt stimmt mein Code? Habe ich etwas nicht beachtet oder muss ich etwas umändern?


----------



## Meniskusschaden (23. Feb 2016)

Mir fällt nur ein Fehler auf. Laut Aufgabenstellung soll charge eine Klassenvariable sein. Bei dir ist es eine Instanzvariable.


----------



## JavaIsTheBest (23. Feb 2016)

Hier ist mein aktueller Code. Aus charge habe ich eine statische Variable gemacht.
Der Typecast hat aus irgendeinem Grund nicht geklappt.


Spoiler: ChargedAccount





```
public class ChargedAccount extends Account {
    private int count;
    private static int charge=10;
  
    public ChargedAccount(String holder){  // Konstruktor von der Oberklasse erben
        super(holder);
    }
    public ChargedAccount(String holder, int balance){
        super(holder,balance);
    }
    public void deposit (int amount) {  //Methoden von der Oberklasse überschreiben
        super.deposit(amount);
        count++;
    }
    public void withdraw (int amount) {
        super.withdraw(amount);
        count++;
    }
    public void charge(){
        super.withdraw(charge*count); //Von welchem Kontoinhaber?
        count=0;
    }
}
```






Spoiler: Main





```
public class AccountTest {
    public static void main(String[] args){
        ChargedAccount charge=new ChargedAccount("Max",3000);
        LimitedAccount limit=new LimitedAccount("Kevin",1000);
      
        Account accountCharge=charge;
        Account accountLimit=limit;
      
        accountCharge.transfer(500, accountLimit);
        accountCharge.transfer(4000, accountLimit);
        accountLimit.transfer(100,accountCharge );
        accountLimit.transfer(7000,accountCharge );
      
         /* Wozu Typecast? Warum aus Account ein ChargedAccount machen?
            Warum ist es möglich aus Account ein ChargedAccount aber umgekehrt nicht?
          */
        (ChargedAccount) accountCharge.charge();
        System.out.println(accountLimit.balance());
        System.out.print(accountCharge.balance());
      
    }

}
```


----------



## Meniskusschaden (23. Feb 2016)

Zur ersten Frage im Quelltext (/* Wozu Typecast? Warum aus Account ein ChargedAccount machen?):
Du hast accountCharge als Variable vom Typ Account deklariert. Man kann darin also ein Objekt vom Typ Account oder einer Unterklasse von Account speichern. Hier wären derzeit noch LimitedAccount und ChargedAccount möglich. Jetzt soll die Methode charge() für das Objekt aufgerufen werden. Der Compiler hat nun ein Problem, denn die Methode ist nur für die Klasse ChargedAccount definiert, er weiß zum Zeitpunkt der Übersetzung jedoch nicht, ob das Objekt wirklich von diesem Typen ist. Es könnte ja auch einem der beiden anderen Typen angehören und für die gibt es keine charge-Methode. Du weißt es aber besser und teilst dem Compiler deshalb durch den Typecast mit, dass es sich um ein ChargedAccount handelt.

Zur zweiten Frage im Quelltext (Warum ist es möglich aus Account ein ChargedAccount aber umgekehrt nicht?):
Umgekehrt ist es nicht nötig, denn ein Objekt vom Typen einer erweiterten Klasse ist gleichzeitig auch immer vom Typen der übergeordneten Klassen. Ein Hund ist auch ein Säugetier und auch ein Tier. Ein Tier muß kein Säugetier sein, sondern es ist vielleicht ein Fisch. Deshalb benötigt man für die eine Richtung einen Typecast und für die andere nicht.



JavaIsTheBest hat gesagt.:


> Der Typecast hat aus irgendeinem Grund nicht geklappt.


Dein Code `(ChargedAccount) accountCharge.charge();` versucht folgendes zu machen: Er ruft auf dem Objekt accountCharge die Methode charge() auf und wendet dann einen Typecast auf das von charge() zurückgelieferte Objekt an. Das ist falsch, denn zum Einen ist der Rückgabetyp von charge() void, so daß überhaupt kein Objekt zurückgeliefert wird, zum Anderen ist es ohnehin nicht das, was du erreichen möchtest. Du willst ja erst den Typecast durchführen und dann auf dem gecasteten Objekt die Methode charge() aufrufen.


----------



## JavaIsTheBest (24. Feb 2016)

So, stimmt das jetzt. 

((ChargedAccount) accountCharge).charge();


----------



## Meniskusschaden (24. Feb 2016)

Sieht gut aus. 

Du kannst in der Test-Klasse noch zwei Zeilen und zwei Variablen einsparen, indem du für die beiden Account-Variablen direkt mit dem jeweiligen Unterklassen-Konstruktor das gewünschte Konto erzeugst. Der Umweg über die Variablen charge und limit ist nicht nötig.


----------

