Frage von gut4fr5g4, 19

Getter und setter richtig verstanden & vererbung erklären?

Mir ist gerade erst in einem Tutorial auf YouTube nebenbei (es gibt garnicht darum) glaube ich klar geworden, was ein getter und setter bringt, nicht das ich jetzt falsch lerne, frage ich lieber noch einmal nach.

So wie ich es verstanden habe ist ein setter so aufgebaut:

int x = 10; public void setter(int x){ this.x = x }

Er erwartet also einen Wert und gibt einer oberen Variable (die, die man verändern will) den mitgegebenen wert.

Der getter:

int x = 10; public void getter(){ return x; }

Er gibt die oben stehende Variable zurück und kann mithilfe von instanzen aus anderen klassen abgerufen werden

Habe ich das so richtig verstanden, oder ist irgendetwas falsch?

Außerdem noch:

Kann mir nocheinmal jemand an einem beispiel bitte ausführlich vererbung erklären (habe dies schon öfters gefragt, aber nie richtig verstanden, deshalb wäre echt nett, wenn ihr euch auf einen neuen versuch einlasst :D)

LG und schönen Abend noch! ;)

Antwort
von regex9, 7

Vom Verständnis ist es dir vielleicht schon klar, aber dennoch birgt dein Code noch einige Fehler.

private int x = 10;

public void setX(int x){ this.x = x; }
public int getX(){ return this.x; }
  1. Das Feld, dem du einen Getter/Setter gibst, sollte mindestens den protected access modifier haben. Sonst macht das Data Hiding-Prinzip keinen großen Sinn mehr.
  2. Laut Konvention setzt sich der Name eines Getters/Setters aus get/set und dem Namen des Felds zusammen.
  3. Da der Getter einen Wert zurückgibt, muss auch ein Rückgabetyp definiert werden.

(...) kann mithilfe von instanzen aus anderen klassen abgerufen werden (...)

Das gilt für Getter und Setter, sofern sie Instanzmethoden sind. Denn es können ja auch Getter/Setter für statische Felder definiert werden.

Vererbung:


Vererbung bedeutet, dass eine Basisklasse um Zustände erweitert wird.
Stell dir vor, du möchtest eine Gruppe an Menschen in einem Programm darstellen: Programmierer, Bauarbeiter und Ärzte. Sie alle haben bestimmte Fähigkeiten und Eigenschaften, die sie untereinander teilen. Z.B. können sie alle essen, schlafen, laufen, sprechen. Um diese Basiseigenschaften nicht immer neu schreiben zu müssen, kann man alle Menschen zu einem abstrakten Oberbegriff vereinen: Mensch. Dies wird die Basis-/Superklasse. Alle Kind-/Subklassen stellen lediglich eine Erweiterung oder konkretere Implermentierung dar.

Codebeispiel (in Java):
class Mensch {
 public void essen() { System.out.println("Isst"); }
 
public void laufen() { System.out.println("Läuft"); }
public void sprechen() { System.out.println("Spricht"); } }
class Programmierer extends Mensch { public void programmieren(){ // ... this.essen(); }
@Override public void sprechen() { System.out.println("Hello World!"); }
}
Programmierer hans = new Programmierer(); hans.laufen(); // Ausgabe: "Läuft"

Wie du siehst, könnte der Programmierer nun auch auf Methoden zugreifen, die von der Basisklasse vererbt wurden (essen, laufen, ...). Ebenso können vererbte Methoden überschrieben werden, um bspw. ein konkreteres Verhalten zu definieren.

1. Vorteil also: Redundanter Programmcode kann eingespart werden. Ein Problem stellt lediglich das Diamond-Dilemma dar. Dazu solltest du allerdings selbst recherchieren.

Der 2. Vorteil entsteht durch Polymorphie, welche auf der Fähigkeit der Vererbung aufbaut:
Mensch mensch = new Programmierer();

Ein Objekt kann in einer Referenz mit dem Typ der Basisklasse gespeichert werden. Dies funktioniert, weil Basis- und Subklasse eine gemeinsame Basis haben. Möglich ist dies logischerweise nur in diese Richtung (Sub in Basis).
Nun zu einem komplexeren Beispiel:
Mensch[] menschen = new Mensch[3];
menschen[0] = new Programmierer();
menschen[1] = new Bauarbeiter();
menschen[2] = new Arzt();

for(Mensch mensch : menschen){ mensch.essen(); mensch.sprechen(); }

Alle aufgeführten Klassen sind Subklassen von Mensch und können daher in dem Array aufgenommen werden. Und da der "offizielle" Datentyp die Methoden essen und sprechen kennt, kann er sie auch in jedem Fall in der Schleife aufrufen.
Konkrete Methoden der Subklasse sind allerdings nicht mehr bekannt, außer man nimmt einen Typecast vor:
menschen[0].programmieren(); // geht nicht, die Klasse Mensch kennt die Methode nicht
((Programmierer)menschen[0]).programmieren(); // nach dem Typecast funktioniert es wieder

Während der Ausgabe der Schleife kommt es übrigens zu einer interessanten Besonderheit der Polymorphie: Der späten Bindung.

Während der Laufzeit wird bei Aufruf der Methoden die Vererbungskette durchlaufen und das letzte Vorkommen der Eigenschaft/Methode genutzt. Im ersten Fall ist dies die überschriebene Methode in der Klasse Programmierer. In den nachfolgenden Fällen ist es die Implementation der Basisklasse.
So können 3 Begriffe definiert werden:
  • Überdeckung: Ein Feld überdeckt ein Feld seiner Basisklasse, wenn es den gleichen Namen und Datentyp besitzt.
  • Überladung: Eine Methode überlädt eine Methode der Basisklasse, wenn sie eine andere Signatur besitzt.
  • Überschreiben: Eine Methode überschreibt eine Methode der Basisklasse, wenn sie die gleiche Signatur besitzt.

Sowie der Begriff der Polymorphie selbst: Polymorphie bezeichnet die Fähigkeit eines Objekts, seinen eigenen Zustand (Eigenschaften und Methoden) zu kennen. Das heißt, auch wenn ein Objekt des Typs Programmierer in eine Referenz des Basistyps gelagert wird, vergisst das Objekt seinen Zustand nicht, und weiß, dass es ein Programmierer ist (nur die Referenz weiß es nicht).


Ausnahmefälle bei der Vererbung:
  • Felder/Methoden mit dem private access modifier werden nicht vererbt.
  • Statische Felder/Methoden werden nicht vererbt, können also auch nicht überschrieben werden.
  • Finale Methoden können nicht überschrieben werden.
  • Finale Klassen können keine Subklassen besitzen.
Antwort
von AndreasGeigerIT, 6

Hallo,

das Grunprinzip von Getter und Setter hast du verstanden. 

Ich möchte es dennoch kurz zusammenfassen:

Generell ist es in der Programmierung wichtig, dass du deine Variablen/Attribute von der Sichtbarkeit so restriktiv wie möglich und so offen wie nötig erstellst. Man sollte hierbei von "außen", also von anderen Objekten immer über die Setter/Getter gehen, da hier kontrolliert Veränderungen der Attribute vorgenommen werden können. 

Du hast beispielsweise die Klasse Auto mit dem Attribut alter (private int alter = 10;). Nun gibt es dafür einen Setter (public void setAlter(int alter){ this.alter = alter;}) und einen Getter (public int getAlter(){ return this.alter;}).

Man kann in dem Setter noch if/else-Bedingungen reinprogrammieren, um damit das Alter kontrolliert durch den Setter zu verändern. Außerdem ist es von der Konvention gängig den Namen des Setters mit set + Name des Attributs zu bilden. Also setAlter beispielsweise. Genauso verläuft es bei den Getter, Also getAlter beispielsweise.

Als Beispiel für die Vererbung nenne ich einfach einmal die Klasse Auto und die Klasse BMW i8. Die Klasse BMW i8 erbt von der Klasse Auto und erbt dadurch auch alle Eigenschaften und Methoden. In der Klasse Auto gibt es bereits eine Methode public void fahren(){}, die die Klasse BMW i8 ebenfalls benötigt. Falls es doch notwendig ist, kann die Klasse BMW i8 diese Methode immer noch erweitern oder komplett neu modifizieren.

Man greift deshalb auf die Vererbung zurück, um Redundanzen zu vermeiden. Soll heißen, wenn es noch Klassen gibt, die die Grundstruktur der Methoden aus der Klasse Auto benötigen, muss man diese nicht jedes mal neu in den Klassen programmieren.

In dem Artikel Programmiersprache Java ist die Programmiersprache Java und wichtige Elemente kurz erklärt http://www.andreasgeiger-it.de/programmiersprache-java/

Viele Grüße

Andreas

Keine passende Antwort gefunden?

Fragen Sie die Community