Um Attributwerte (Objekteigenschaften) gegen Fehler abzusichern, überprüft man diese in Methoden. Diese Methoden heißen Setter zum Ändern von Attributwerten und Getter zum Abrufen von Daten. Um nun sicherzustellen, dass die Daten immer über diese Methoden geändert und abgerufen werden kappselt man die Attribute, d.h. man macht die Attribute privat. Dadurch kann nur noch in der Klasse auf die Attribute direkt zugegriffen werden, von außerhalb nur über die Setter und Getter.
In diesem Artikel lernst Du wie man Attributwerte mit set- und get-Methoden absichert, die Bedeutung der Datenkapselung mit public und private sowie das UML-Klassendiagramm kennen.
Leuchtmittel
werden folgende Eigenschaften für die Leuchtmittel definiert: Leistungsaufnahme P in W (Watt), Lichtstrom Φ in lm (Lumen). Berechnen kann man hieraus die Lichtausbeute η in lm/W (Lumen pro Watt).
class Leuchtmittel: def __init__(self, leistung = 2.5, lumen = 340): self.leistung = leistung self.lumen = lumen def __str__(self): return self.__class__.__name__ + f" {self.leistung} W, 🔆 {self.lumen} lm und η = {self.lumen/self.leistung} lm/W"
Lampe
Eine Wagenradlampe der Klasse Beleuchtung
besteht aus Objekten der Leuchtmittel. Wir erstellen nun ein Objekt:
class Beleuchtung: l1 = Leuchtmittel(2.5, 340) l2 = Leuchtmittel(3, 420) print(l1) print(l2) #Die Leistung wird mit einem fehlerhaften Wert manipuliert. l2.leistung = -42.0 print(l2)
Folgende Ausgabe wird erzeugt:
Leuchtmittel 2.5 W, 🔆 340 lm und η = 136.0 lm/W
Leuchtmittel 3 W, 🔆 420 lm und η = 140.0 lm/W
Leuchtmittel -42.0 W, 🔆 420 lm und η = -10.0 lm/W
Der Benutzer kann fehlerhafte Werte setzen wodurch nicht nur der Wert, sondern auch nachfolgende Berechnungen fehlerhaft sind.
Leuchtmittel
Wir ersetzen den sogenannten Modifier der Attribute in der Klasse Leuchtmittel
beschränkt. Diesen Vorgang nennt man Kapselung. Man schirmt die Attribute vom Zugriff aus anderen Klassen ab.
Die Änderung von gekapselten Werten erlaubt man dann nur noch in den sogenannten set-Methoden; für den Wertzugriff verwendet man get-Methoden. Der indirekte Zugriff auf die Leuchtmittelattribute erfolgt aus der Klasse Lampe
:
class Beleuchtung: l1 = Leuchtmittel(2.5, 340) print(l1) #Die Leistung wird mit fehlerhaft manipuliert. l1.setLeistung(-2.5) print(l1)
class Leuchtmittel: def __init__(self, leistung = 2.5, lumen = 340): self.setLeistung(leistung) self.lumen = lumen #setter und getter für Leistung def setLeistung(self, leistung): if (leistung >= 0): self.__leistung = leistung #geschütztes Attribut else: print("Wert fehlerhaft, der Wert bleibt unverändert.") def getLeistung(self): return self.__leistung def __str__(self): return self.__class__.__name__ + f" {self.__leistung} W, 🔆 {self.lumen} lm und η = {self.lumen/self.__leistung} lm/W"
Modifier | Die Klasse selbst | Unterklassen | sonstige Klassen |
---|---|---|---|
private (zwei Unterstriche) | ✓ | ✗ | ✗ |
protected (ein Unterstrich) | ✓ | ✓ | ✗ |
public (kein Unterstrich) | ✓ | ✓ | ✓ |
Erstelle die Klasse Leuchtmittel und Beleuchtung.
Leuchtmittel
und Beleuchtung
. Programmiere alle Methoden wie im Eingangsbeispiel. Vergiss dabei nicht in der to-String-Methode auch die Lichtausbeute auszugeben.l2 = Leuchtmittel(-2, 340)
,l2 = Leuchtmittel(0, 340)
,l2 = Leuchtmittel("0", 340)
.__leistung
gegen diese Fehler ab.Mit Setter und Getter wird der Zugriff auf Variablen mitunter unlesbar. Betrachten wir hierzu folgendes Beispiel. In der Klasse Beleuchtung wird die Leistung von l3 mit den Werten von l1 und l2 berechnet.
class Beleuchtung: l1 = Leuchtmittel(2.5,340) l2 = Leuchtmittel(1.5,200) l3 = Leuchtmittel() #Die Leistung von l3 wird mit den Werten von l1 und l2 berechnet. l3.setLeistung(l1.getLeistung()+l2.getLeistung()) print(l3)
Durch Properties wird der Code wieder lesbarer. Wir können die Variablen verwenden als ob sie öffentlich wären, sind sie aber nicht.
class Leuchtmittel: def __init__(self, leistung = 2.5, lumen = 340): ... def setLeistung(self, leistung): ... def getLeistung(self): ... def __str__(self): ... #property leistung = property(getLeistung, setLeistung) class Beleuchtung: l1 = Leuchtmittel(2.5,340) l2 = Leuchtmittel(1.5,200) l3 = Leuchtmittel() #Die Leistung von l3 wird mit den Werten von l1 und l2 berechnet. l3.leistung = l1.leistung + l2.leistung print(l3)
Nenne die Klasse, welche auf ein private
Attribut Zugriff hat.
Wähle eine Antwort.
Nenne Vorteile der Kapselung.
Wähle zwei Antworten.
Finde die Anzahl der Fehler im folgenden Quelltext.
def setLeistung(self, __leistung): if (leistung >= 0): self.leistung = leistung else: print("Wert fehlerhaft")
Finde die Anzahl der Fehler im folgenden Quelltext.
def __init__(self, leistung): self.leistung = leistung def getLeistung(self, leistung): return self.__leistung
Bestimme die zugehörige Konstruktormmethode, zum Konstruktoraufrufs2 = Schaf(alter = 20, gewicht = 23.3)
. Wähle eine Antwort.
def __init__(self, gewicht, alter)
def __init__(gewicht=1.0, alter=1)
def __init__(self, alter, gewicht, c="C")
def __init__(self, 20, 3)
Beschreibe einen Konstruktor.
Wähle beliebig viele Antworten.
Mit Hilfe von Exceptions lassen sich verschiedene Fehlermeldungen abfangen.
class Beleuchtung: l1 = Leuchtmittel(2.5,340) l2 = Leuchtmittel(1.5,200) l3 = Leuchtmittel() #Die Leistung von l3 wird mit den Werten von l1 und l2 berechnet. l3.setLeistung(l1.getLeistung()+l2.getLeistung()) print(l3)
Durch Properties wird der Code wieder lesbarer. Wir können die Variablen verwenden als ob sie öffentlich wären, sind sie aber nicht.
class Leuchtmittel: def __init__(self, leistung = 2.5, lumen = 340): ... def setLeistung(self, leistung): ... def getLeistung(self): ... def __str__(self): ... #property leistung = property(getLeistung, setLeistung) class Beleuchtung: l1 = Leuchtmittel(2.5,340) l2 = Leuchtmittel(1.5,200) l3 = Leuchtmittel() #Die Leistung von l3 wird mit den Werten von l1 und l2 berechnet. l3.leistung = l1.leistung + l2.leistung print(l3)
Die Schafe sollen mit set-get-Fähigkeiten und Konstruktoren ausgestattet werden.
Schaf
mit folgenden set-get-Methoden:public void setName(String name) {..}
public void setAlter(int alter) {..}
public void setGewicht(double gewicht) {..}
,public void setGewicht(int mengeGras, int mengeKohl ) {..}
,public String getName() {..}
,public int getAlter() {..}
,public double getGewicht() {..}
.Schaf
mit einem neuen Standardkonstuktor:public Schaf( ) {..}
. Initialisiere den Namen mit "noname", das Alter mit 1 Jahr sowie das Gewicht mit 0.0 kg.Schaf
mit dem weiteren Konstuktor:public Schaf(String name, int alter, double gewicht) {..}
.Schafherde
die neuen Methoden und Konstruktoren ausführlich. Lass alle Änderungen der Attribute jeweils anzeigen.Erweitere die Klasse Auto und Fuhrpark.
Auto
mit set- und get-Methoden.Auto
auf private
Fuhrpark
durch Aufrufe der set- und get-Methoden und teste so die Funktionalität der Klasse Auto
.Auto
mit zwei Konstruktormethoden, den Standardkonstruktor mit Initalwerten und einem Konstruktor mit Parameterliste.UML (engl. unified modeling language) ist eine grafische Modellierungssprache zur Spezifikation, Konstruktion und Dokumentation von Software-Teilen und anderen Systemen. UML besteht aus vielen Diagrammtypen. Ein Typ davon ist das Klassendiagramm.
Ein Klassendiagramm stellt eine Klasse übersichtlich und strukturiert dar. Es ist von der Form her rechteckig und besteht aus drei Teilen:
+
für public
und -
für private
) und Datentyp,
Man beachte, das statische Methoden und Attribute unterstrichen werden. Der Vorteil statischer Methoden liegt darin, dass sie ohne die Erzeugung eines Objekts aufrufbar sind: Auto.setMwSt(19.0);
. Nachteilig wirkt sich aus, dass der Speicher immer belegt wird.
Was das Klassendiagramm nicht sagt:
Auto |
- farbe : String - leistung : int - preis : double - mehrwertsteuer : double |
+ Auto (String farbe, int leistung, double preis) + setFarbe (String color) : void + setLeistung (int power) : void + setMwSt (double mwst) : void + getFarbe () : String + getLeistung () : int + getMwSt () : double + fahrenStrecke (int km) : void + tanken (int menge) : void |
Schreibe UML-Klassendiagramme.
Auto
.Fuhrpark
.Schaf
.Schreibe weitere Klassenpaare.
Neben den Klassenpaaren Schaf
und Schafherde
sowie Auto
und Fuhrpark
, gibt es weitere Klassenpaare.
Wohnmobil
und Campingplatz
.Pizza
und Menue
.Sensor
und Home
.Speichert man die verschiedenen Objekte direkt beim Erzeugen in einer ArrayList
können mit Hilfe von Schleifen automatisierte Ausgaben und Auswertungen aller Objekte generiert werden. Dabei muss im Vergleich zu einem array
die genaue Anzahl der Objekte vorab nicht bekannt sein. Mit der add(..)
Methode wird ein Element dem Container hinzugefügt.
import java.util.ArrayList; public class SchafherdeArrayList { public static void main(String[] args) { //Anlegen einer ArrayList namens schafListe ArrayList<Schaf> schafListe = new ArrayList<Schaf>(); //Hinzufügen von Einträgen mit der Methode add(..) schafListe.add(new Schaf("Emma", 20, 50.0)); schafListe.add(new Schaf("Berta", 8, 30.0)); } }
ArrayList
ist eine Klasse, die als Container für eine Liste von Objekten dient. Ähnlich wie bei einem Array kann man auf die Objekte über einen Index zugreifen, jedoch muss die Objektanzahl in der Liste anfangs nicht angegeben werden.
Um nun Standardwerte zu vergeben oder beim Erzeugen des Objekts die Attribute zu setzen, werden entsprechende Konstruktormethoden erstellt.
Des weiteren benötigen wir wie gehabt entsprechende set- und get-Methoden.
public class Schaf{ private String name; private int alter; private double gewicht; //Konstruktor public Schaf (String n, int a, double g){ this.name = n; this.alter = a; this.gewicht = g; } //set- und get-Methoden ... }
//Ausgabe aller Schafe und deren Alter for (int i=0; i<schafListe.size(); i++) { Schaf schaf = schafListe.get(i); System.out.println("Schaf "+(i+1)+": "+schaf.getName()); System.out.println("Alter: "+schaf.getAlter()); } //Berechnung des mittleren Herdenalters int gesamt = 0; for (Schaf schaf: schafListe) { gesamt += schaf.getAlter(); } double herdenalter = (double)gesamt/schafListe.size(); System.out.printf("Herdenalter: %.1f",herdenalter);
In der for-Schleife wird über die size()
Mehtode die Anzahl der Elemente abgefragt. Die get(..)
Methode gibt das Element am angegebenen Index zurück.
for-each-Schleifen iterrieren über alle Datenstrukturen deren Elemente aufzählbar sind. In Java werden diese mit dem : Operator gekennzeichnet. Dabei ist Schaf
der Datentyp des Elements und schaf
das Elementobjekt welches aktuell betrachtet wird. Das Containerobjekt schafListe
gehört zur Klasse ArrayList
.
For-each-Schleifen haben eine kürzere und übersichtlichere Syntax. For-Schleifen erlauben einen Zugriff auf den Schleifenzähler.
add(..)
, size()
und get(..)
sind die essentiellen Methoden der Klasse ArrayList
.
Realisiere eine Bücherei in der Bücher mit Titel, Autor und Bewertung gespeichert werden sollen.
Book
und Library
. Book
die Attribute title
, author
, rating
hinzu sowie entsprechende set- und get-Methoden.Library
eine ArrayList
namens booklist
hinzu und erzeuge drei Einträge wie bspw. booklist.add(new Book("Herr der Ringe", "J.R.R. Tolkien", 4.8));
.Für Objekte der Klasse Schaf
soll eine ArrayList erstellt werden.
Wähle eine Antwort.
ArrayList box = new ArrayList();
ArrayList<Schaf> box = ArrayList<Schaf>();
ArrayList<Schaf> box = new ArrayList<Schaf>();
ArrayList schafListe = new ArrayList();
Erkläre die Klasse ArrayList
.
Wähle eine Antwort.
Finde die Anzahl der Fehler im folgenden Quelltext.
import java.util.ArrayList; public class Pizzamenu { public static void main(String[] args) { ArrayListmenue = new ArrayList (); menue1.add(new schaf()); } }
Finde die Anzahl der Fehler im folgenden Quelltext.
public class Pizza{ private String name; public Pizza (String name, double preis){ this.name = namen; this.preis = preis; } }
In der ArrayList box
sind 3 Schafe im Alter von jeweils 3 Jahren.
int i = 3;
for (Schaf schaf: box) {
i += schaf.getAlter()-1;
}
Bestimme den Wert von i
. Wähle eine Antwort.
In der ArrayList box
sind zwei Schafe namens Emma und Berta.
for (int i=0; i<box.size(); i++) {
Schaf schaf = box.get(i);
System.out.print(schaf.getName());
}
Bestimme die Ausgabe. Wähle eine Antwort.
Mit Hilfe der toString-Methode kann man Objekte direkt ausgeben. Wir erstellen die Klasse Schaf mit zwei Konstrukoren und der toString-Mehtode. Diese Methode gibt eine Zeichenkette zurück und hat keine Übergabeparameterzwei Schafe mit Hilfe des Konstruktors
public class Schaf{ private String name; private int alter; private double gewicht; //Konstruktor public Schaf (String n, int a, double g){ this.name = n; this.alter = a; this.gewicht = g; } //toString-Methode public String toString (){ return "Name: "+this.name+"\nAlter: "+this.alter; } }
In der Klasse Schafherde
können wir nun die Objekte direkt ausgeben.
Man beachte das in der Methode printl(..)
, bei einem Objekt als Parameter, die toString-Methode aufgerufen wird.
public class Schafherde { public static void main(String[] args) { //Konstruktoraufruf mit Parameter Schaf s1 = new Schaf("Emma",20,50.0); Schaf s2 = new Schaf("Berta",8,30.0); //Objektinformationen ausgeben System.out.println(s1); System.out.println(s2); } }
das Objekt, -e | Objekte haben Eigenschaften (engl. states) und Fähigkeiten (engl. behaviors). Diese werden in einer zugehörigen Klasse festgelegt. |
die Klasse, -n | Eine Klasse beschreibt, welche Eigenschaften und Fähigkeiten ein Objekt haben darf und stellt somit den Bauplan von Objekten bereit. |
die Methode, -en | Fähigkeiten von Objekten werden in Methoden beschrieben. |
das Attribut, -en | Eigenschaften von Objekten werden in Attributen (Variablen) festgelegt. |
der Modifier, ~ | legt die Sichtbarkeit von Eigenschaften und Fähigkeiten fest, also ob diese bspw. privat oder öffentlich zugänglich sind |
die Kapselung, - | die Sichtbarkeit der Attribute einer Klasse wird auf private gesetzt und so schirmt man die Attribute vom Zugriff aus anderen Klassen ab. |
die set-, get-Methoden, - | Methoden die die abgeschirmten Attribute setzen oder auslesen. |
der Konstruktor, -en | Methode welche die Initialisierung der Parameter bei Objekterzeugung ermöglicht |
das Überladen des Konstruktors | Existieren mehrere Methoden gleichen Namens spricht man vom Überladen. So kann bspw. mit mehreren Konstruktoren ein unterschiedlicher Initialisierungsgrad erreicht werden. |
die ArrayList | eine Klasse, die als Container für eine Liste von Objekten dient |