Klassen und Objekte
Kurz gesagt: Eine Klasse beschreibt einen neuen Typ mit Feldern, und ein Objekt ist ein konkretes Exemplar davon, erzeugt mit new; die Variable zeigt nur auf das Objekt.
Problem
Die Preise sind durcheinander
Du schreibst den Warenkorb eines Onlineshops. Jedes Produkt hat einen Namen und einen Preis, also speicherst du sie in zwei Arrays: An Index 0 stehen der Name und der Preis des ersten Produkts, an Index 1 die des zweiten.
Du willst das Teuerste ganz vorne haben und tauschst die Preise:
String[] names = { "Brot", "Milch", "Kaffee" };double[] prices = { 1.20, 2.10, 7.50 };
// Das Teuerste zuerst: den ersten und den dritten Preis tauschen.double temp = prices[0];prices[0] = prices[2];prices[2] = temp;
for (int i = 0; i < names.length; i++) { System.out.println(names[i] + ": " + prices[i] + " €");}Brot: 7.5 €Milch: 2.1 €Kaffee: 1.2 €Das Brot kostet jetzt 7,50 €. Die Preise sind getauscht, die Namen aber nicht. Die beiden Arrays müssen sich immer gemeinsam ändern, aber nichts zwingt dich dazu. Kommt ein drittes Array für die Stückzahlen dazu, musst du an drei denken.
Die Idee
Ein Produkt, ein Ort
Der Name und der Preis sind keine getrennten Dinge. Sie sind Teile eines Produkts. Wir wollen einen Typ „Produkt“, so wie es int für Zahlen und String für Text gibt.
So einen Typ machst du dir selbst. Er heißt Klasse:
class Product { public String name; public double price; public int quantity;}Die Variablen in der Klasse sind ihre Felder. Jedes Produkt hat seinen eigenen Namen, seinen eigenen Preis und seine eigene Stückzahl.
Die Klasse ist nur eine Beschreibung: „Jedes Produkt hat einen Namen, einen Preis und eine Stückzahl.“ Ein Produkt gibt es noch nicht.
public heißt, dass die Felder auch von außen sichtbar sind, aus main. Warum wir genau das schreiben und was das Gegenteil ist, siehst du in der Lektion „Kapselung“.
Die Idee
new: von der Beschreibung zum Produkt
Ein konkretes Produkt erzeugst du aus der Klasse mit new. Es heißt Objekt. An seine Felder kommst du mit einem Punkt:
class Product { public String name; public double price; public int quantity;}
public class Main { public static void main(String[] args) { Product bread = new Product(); bread.name = "Brot"; bread.price = 1.20; bread.quantity = 2;
Product coffee = new Product(); coffee.name = "Kaffee"; coffee.price = 7.50; coffee.quantity = 1;
System.out.println(bread.name + ": " + bread.price * bread.quantity + " €"); System.out.println(coffee.name + ": " + coffee.price * coffee.quantity + " €"); }}Brot: 2.4 €Kaffee: 7.5 €- Die Klasse steht außerhalb von public class Main, darüber. Eine Datei kann mehrere Klassen haben.
Product breadist eine Variable vom TypProduct, so wieint countvom Typintist.new Product()erzeugt ein neues Objekt. Jedes Objekt hat eigene Felder: Das Brot und der Kaffee kommen sich nicht in die Quere.bread.priceist „der Preis des Brots“. Du liest und schreibst ihn wie eine gewöhnliche Variable.
Jetzt stehen der Name und der Preis des Produkts an einem Ort. Verschiebst du das Produkt, wandern sie mit.
Probier es aus
Nichts ist ausgefüllt
Wenn du ein Produkt erzeugst und nichts ausfüllst, was steht dann in seinen Feldern?
Was gibt das Programm aus?
Product item = new Product();System.out.println(item.name);System.out.println(item.price);System.out.println(item.quantity);Die Felder eines neuen Objekts haben immer einen Standardwert: 0 für Zahlen, false für Wahrheitswerte und null für Text. null heißt „nichts“. Lokale Variablen in main haben keinen solchen Wert. Dort verlangt der Compiler, dass du sie füllst, bevor du sie liest.
Probier es aus
Was fehlt?
Was gehört in die Lücke, damit es ein neues Produkt gibt?
Product milk = Product();
milk.name = "Milch";
milk.price = 2.10;new: Nur new erzeugt ein Objekt. Ohne new hast du nur eine Variable, die noch auf nichts zeigt.Sieh es dir an
Die Variable zeigt auf das Objekt
Du willst den Kaffee im Angebot verkaufen, also machst du eine „Kopie“, um seinen Preis zu ändern:
Product coffee = new Product();coffee.price = 10;Product sale = coffee;sale.price = 8;System.out.println(coffee.price); // 8.0Schritt für Schritt, in Worten
- new erzeugt das Objekt, und seine Felder bekommen Startwerte. coffee bekommt einen Pfeil darauf.
- Dem Pfeil von coffee nach: Der Preis des Objekts wird 10.
- sale = coffee kopiert den Pfeil, nicht das Objekt. Zwei Pfeile, ein Objekt.
- Dem Pfeil von sale nach: Der Preis im selben Objekt wird 8.
- coffee zeigt auf dasselbe Objekt, also wird 8.0 ausgegeben.
Der Preis des Kaffees ist auch 8 geworden. Der Grund: Die Variable coffee ist nicht das Objekt selbst. Das Objekt liegt getrennt im Speicher, und coffee merkt sich, wo es ist: einen Pfeil auf das Objekt. So eine Variable heißt Referenz.
sale = coffee kopiert den Pfeil, nicht das Objekt. Jetzt zeigen zwei Pfeile auf ein Objekt, deshalb sieht man die Änderung über sale auch über coffee.
Dasselbe hast du in der Lektion über Arrays gesehen: sale = prices gab demselben Array einen zweiten Namen. Ein Array ist auch ein Objekt.
Die Idee
Der Rabatt funktioniert jetzt
Im Modul „Methoden“ hat der Rabatt nicht funktioniert: Die Methode bekam eine Kopie des Preises, änderte die Kopie, und die Kopie ging verloren. Mit einem Objekt ist das anders:
static void discount(Product p, double percent) { p.price = p.price * (100 - percent) / 100;}
Product coffee = new Product();coffee.price = 10;discount(coffee, 10);System.out.println(coffee.price);9.0Der Parameter ist immer noch eine Kopie, aber eine Kopie des Pfeils. Er zeigt auf dasselbe Objekt, deshalb bleibt die Änderung an p.price auch nach der Methode erhalten.
Genauer, für Neugierige
Wenn die Methode ein neues Objekt in den Parameter legt, verschiebt sie nur ihre eigene Kopie des Pfeils. Das Objekt draußen ändert sich nicht:
static void reset(Product p) { p = new Product(); p.price = 0;}
Product coffee = new Product();coffee.price = 10;reset(coffee);System.out.println(coffee.price);10.0Die Idee
null: ein Pfeil ins Nichts
Eine Variable vom Typ einer Klasse kann auf nichts zeigen. Dann steht in ihr null. Wenn du über sie ein Feld lesen willst, gibt es kein Objekt, aus dem du es lesen kannst:
Product gift = null;System.out.println(gift.name);Das Programm lässt sich kompilieren, bricht aber mit einem Fehler ab, sobald es diese Zeile erreicht:
Exception in thread "main" java.lang.NullPointerException: Cannot read field "name" because "gift" is nullDas ist der häufigste Fehler mit Objekten. Was eine „Exception“ ist und wie man sie fängt, siehst du im Modul „Fehler und Exceptions“.
Vorsicht bei Arrays von Objekten. new Product[3] macht drei Plätze für Pfeile, nicht drei Produkte. Jeder Platz ist null, bis du dort new Product() hineinlegst:
Product[] cart = new Product[3];System.out.println(cart[0] == null);cart[0] = new Product();cart[0].name = "Brot";System.out.println(cart[0].name);trueBrotProbier es aus
Finde den Fehler
Das Programm soll „Brot“ und „Milch“ ausgeben. Stattdessen gibt es zweimal „Milch“ aus. In welcher Zeile steckt der Fehler?
Wähle die Zeile mit dem Fehler.
Product milk = bread; erzeugt kein neues Produkt. Jetzt zeigen milk und bread auf dasselbe Objekt, und der Name „Milch“ ersetzt „Brot“. Die Korrektur ist Product milk = new Product();.
Übung
Deine Klassen
1. Buch. Eine Klasse Book mit Feldern für den Titel und den Autor. Erzeuge zwei Bücher und gib sie aus.
Der Prozess von Franz KafkaEffi Briest von Theodor Fontane2. Auto. Eine Klasse SimpleCar mit einem Feld für die Geschwindigkeit. Erzeuge ein Auto (seine Geschwindigkeit ist 0), erhöhe die Geschwindigkeit um 10 und gib sie aus. In der Lektion „Instanzmethoden“ wird daraus eine Methode des Autos.
Geschwindigkeit nach dem Beschleunigen: 103. Der Warenkorb. Der Warenkorb von der ersten Karte, diesmal mit einem Array aus drei Product-Objekten: Brot 1,20 € (2 Stück), Milch 2,10 € (1 Stück), Kaffee 7,50 € (1 Stück). Gib den Betrag für jede Zeile und die Gesamtsumme aus. Denk daran, dass nach new Product[3] noch keine Produkte im Array sind.
Brot x2: 2.4 €Milch x1: 2.1 €Kaffee x1: 7.5 €Summe: 12.0 €4. Das Teuerste zuerst. Sortiere denselben Warenkorb nach Preis, vom teuersten zum billigsten, mit dem Bubblesort aus der Lektion über Arrays. Diesmal tauschst du ganze Produkte, deshalb wandern der Name und der Preis zusammen.
Kaffee: 7.5 €Milch: 2.1 €Brot: 1.2 €Weitere Aufgaben
- Schüler. Eine Klasse
Studentmit einem Namen und drei Noten (drei Felder). Erzeuge zwei Schüler und gib die Durchschnittsnote von jedem aus. - Ein Buch, zwei Namen. Erzeuge ein Buch, speichere es in zwei Variablen und ändere den Titel über die zweite. Gib den Titel über die erste aus. Erkläre in Worten, warum das so ist.
Test
Teste dich
Verwandte Lektionen
Abschnitt „Verwandte Lektionen“- Baut auf: Schleifen · Arrays · Methoden · Parameter und return
- Geht weiter in: Konstruktoren und this · Instanzmethoden · Kapselung · static: was alle Objekte teilen
- Aufgaben zum Thema: Klassen und Objekte