Kapitel 7
Klassen und Objekte
Bisher hattest du einzelne Variablen und Arrays. Ein Bankkonto besteht aber aus Inhaber und Kontostand, und es kann Geld annehmen. Eine Klasse fasst solche Daten und die passenden Methoden zusammen. Sie ist der Bauplan, mit new baust du daraus beliebig viele Objekte.
In den Aufgaben steht jede Klasse in einer eigenen Datei mit ihrem Namen, z. B. Account.java. In den Beispielen hier steht alles in einer Datei, damit du es auf einen Blick siehst. Dann darf nur Main public sein.
Attribute, Konstruktor, Methoden
- Attribute (Felder) sind die Daten jedes Objekts. Sie sind
private: Nur die Klasse selbst kommt an sie heran. Von außen geht das über Methoden wiegetBalance(), die Getter. Das heißt Kapselung. - Der Konstruktor heißt wie die Klasse, hat keinen Rückgabetyp und läuft bei
new Account("Ada"). Er füllt die Attribute. this.ownerist das Attribut des Objekts,ownerallein der Parameter. Heißen beide gleich, brauchst duthis.- Methoden ohne
staticarbeiten mit den Attributen des Objekts, für das du sie aufrufst:ada.deposit(50)ändert nur Adas Konto. toString()gibt an, wie ein Objekt als Text aussieht.println(ada)ruft sie automatisch auf.
final vor einem Attribut heißt: Es wird einmal im Konstruktor gesetzt und danach nie mehr geändert.
class Account {
private final String owner;
private double balance;
public Account(String owner) {
this.owner = owner;
this.balance = 0;
}
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
public double getBalance() {
return balance;
}
public String toString() {
return owner + ": " + balance + " €";
}
}
public class Main {
public static void main(String[] args) {
Account ada = new Account("Ada");
Account bob = new Account("Bob");
ada.deposit(50);
ada.deposit(-10);
bob.deposit(20);
System.out.println(ada);
System.out.println(bob);
System.out.println("Ada has " + ada.getBalance());
}
}static und Konstanten
Ein Attribut ohne static gibt es in jedem Objekt einmal. Ein Attribut mit static gibt es nur einmal für die ganze Klasse, alle Objekte teilen es. Damit zählst du zum Beispiel, wie viele Objekte es schon gibt. Eine static-Methode rufst du über den Klassennamen auf: Ticket.issued(). Sie hat kein this und kann deshalb keine normalen Attribute lesen. Darum war bisher alles static: main läuft, ohne dass es ein Objekt gibt.
static final macht eine Konstante, geschrieben in Großbuchstaben: public static final int MAX = 7;.
Eine Klasse kann mehrere Konstruktoren haben. Mit this(...) in der ersten Zeile ruft einer den anderen auf, so steht die Logik nur an einer Stelle:
public Duration(int minutes, int seconds) {
this(minutes * 60 + seconds);
}class Ticket {
public static final String OFFICE = "Town hall";
private static int counter = 0;
private final int number;
public Ticket() {
counter++;
this.number = counter;
}
public int getNumber() {
return number;
}
public static int issued() {
return counter;
}
}
public class Main {
public static void main(String[] args) {
Ticket a = new Ticket();
Ticket b = new Ticket();
Ticket c = new Ticket();
System.out.println(Ticket.OFFICE);
System.out.println("a: " + a.getNumber());
System.out.println("c: " + c.getNumber());
System.out.println("Issued: " + Ticket.issued());
}
}Records
Für Klassen, die nur Daten zusammenhalten, gibt es eine Kurzform: record Point(int x, int y) { }. Diese Zeile erzeugt private final Attribute, einen Konstruktor, die Getter x() und y() (ohne get), ein toString() wie Point[x=3, y=4] und ein equals, das die Werte vergleicht.
Ein Record ist unveränderlich. Soll sich etwas „ändern“, gibt eine Methode einen neuen Record zurück, wie moved im Beispiel. Math.abs(n) liefert den Betrag einer Zahl, also ohne Vorzeichen.
record Point(int x, int y) {
public int distance(Point p) {
return Math.abs(x - p.x()) + Math.abs(y - p.y());
}
public Point moved(int dx, int dy) {
return new Point(x + dx, y + dy);
}
}
public class Main {
public static void main(String[] args) {
Point a = new Point(3, 4);
Point b = a.moved(1, -2);
System.out.println(a);
System.out.println(b);
System.out.println("x of b: " + b.x());
System.out.println("Distance: " + a.distance(b));
System.out.println(a.equals(new Point(3, 4)));
System.out.println(a == new Point(3, 4));
}
}Typische Fehler
Attribut verdeckt
Heißt ein Parameter oder eine lokale Variable wie ein Attribut, verdeckt sie es. Beide Zeilen sehen richtig aus und ändern das Attribut nicht:
public Player(String name) { name = name; // parameter assigned to itself } public void addPoints(int points) { int score = this.score + points; // new local variable }Richtig ist
this.name = name;undscore = score + points;ohneint.Objekte mit == vergleichen
==prüft, ob es dasselbe Objekt ist. Zwei Punkte mit gleichen Werten sind trotzdem zwei Objekte, wie die letzte Zeile im Record-Beispiel zeigt. Für gleiche Werte gibt esequals, bei Records automatisch.toString vergessen
Ohne eigenes
toString()gibtprintln(book)etwas wieBook@1b6d3586aus. Die Methode muss genaupublic String toString()heißen.Attribut aus static-Methode lesen
In einer
static-Methode gibt es kein Objekt und damit keinthis. Greifst du dort auf ein normales Attribut zu, meldet der Compilernon-static variable cannot be referenced from a static context.Leere Plätze im Objekt-Array
new Measurement[7]legt sieben leere Plätze an, allenull. Rufst du darauf eine Methode auf, bricht das Programm mitNullPointerExceptionab. Lauf nur über die Plätze, die du schon gefüllt hast.