static: was alle Objekte teilen
Kurz gesagt: Ein statisches Feld oder eine statische Methode gehört zur Klasse, nicht zum Objekt: Alle Objekte sehen einen gemeinsamen Wert, zum Beispiel einen Zähler der erzeugten Objekte.
Problem
Jedes Produkt ist Nr. 1
Der Shop will, dass jedes neue Produkt die nächste Nummer bekommt: 1, 2, 3… Du legst einen Zähler nextId in die Klasse. Der Konstruktor gibt dem Produkt die aktuelle Nummer und erhöht den Zähler:
class Product { private int nextId = 1; private int id; private String name;
public Product(String name) { this.name = name; id = nextId; nextId++; }
@Override public String toString() { return "Nr. " + id + " " + name; }}
Product bread = new Product("Brot");Product milk = new Product("Milch");Product coffee = new Product("Kaffee");System.out.println(bread);System.out.println(milk);System.out.println(coffee);Nr. 1 BrotNr. 1 MilchNr. 1 KaffeeAlle sind Nr. 1. Der Grund ist, dass nextId ein Feld des Objekts ist, genau wie der Name. Jedes neue Produkt bekommt seinen eigenen Zähler, der bei 1 beginnt. Der Zähler des Brotes kommt nie bei der Milch an.
Die Idee
Ein Feld der Klasse, nicht des Objekts
Der Zähler gehört nicht zu einem Produkt. Alle Produkte teilen ihn sich. Füge static hinzu:
private static int nextId = 1;Ein static-Feld ist ein Feld der Klasse. Es gibt eines, egal wie viele Objekte du erzeugst, und alle Objekte teilen es sich:
class Product { private static int nextId = 1; private int id; private String name;
public Product(String name) { this.name = name; id = nextId; nextId++; }
@Override public String toString() { return "Nr. " + id + " " + name; }}
public class Main { public static void main(String[] args) { Product bread = new Product("Brot"); Product milk = new Product("Milch"); Product coffee = new Product("Kaffee"); System.out.println(bread); System.out.println(milk); System.out.println(coffee); }}Nr. 1 BrotNr. 2 MilchNr. 3 KaffeeDas Brot nimmt die 1 und macht den Zähler zu 2. Die Milch sieht denselben Zähler, nimmt die 2 und macht ihn zu 3.
private static int nextId = 1;
public Product(String name) { this.name = name; id = nextId; nextId++;}
Product bread = new Product("Brot");Product milk = new Product("Milch");Product coffee = new Product("Kaffee");Schritt für Schritt, in Worten
- nextId ist static: ein Feld in der Klasse, nicht eines in jedem Objekt.
- new Product("Brot"): ein neues Objekt. Der Konstruktor speichert den Namen.
- id = nextId: Das Objekt nimmt die aktuelle Nummer, 1.
- nextId++ ändert den gemeinsamen Zähler: Jetzt ist er 2.
- Milch: derselbe Zähler. Es nimmt die 2 und macht ihn zu 3.
- Kaffee: Es nimmt die 3 und macht ihn zu 4.
- Es gibt einen Zähler für alle, deshalb sind die Nummern der Reihe nach.
Wenn das Feld public static ist, erreichst du es von außen über den Namen der Klasse (Product.nextId), nicht über ein Objekt.
Probier es aus
Gemeinsam und eigen
Was gibt das Programm aus?
class Order { public static int count = 0; public int items = 0;
public Order() { count++; items++; }}
Order a = new Order();Order b = new Order();Order c = new Order();System.out.println(Order.count + " " + c.items);count ist static: ein Zähler für alle Bestellungen, dreimal erhöht. items ist ein Feld des Objekts: Jede Bestellung hat ihr eigenes, einmal erhöht.Die Idee
Eine statische Methode: Arbeit ohne Objekt
Dasselbe gilt für Methoden. Eine static-Methode ist eine Methode der Klasse. Du rufst sie über den Namen der Klasse auf, ohne new:
class Calculator { public static int add(int a, int b) { return a + b; }
public static double average(int[] values) { int sum = 0; for (int v : values) { sum += v; } return (double) sum / values.length; }}
System.out.println(Calculator.add(10, 20));int[] grades = { 5, 6, 4, 6 };System.out.println(Calculator.average(grades));System.out.println(Math.max(3, 8));305.258Calculator.add braucht kein Objekt: Alles, was sie braucht, kommt als Parameter. Die Methoden von Math sind genauso: Math.max, Math.sqrt. Niemand schreibt new Math().
Jetzt ist klar, warum main static ist. Wenn das Programm startet, gibt es noch keine Objekte. Die Laufzeitumgebung ruft main direkt über die Klasse auf. Deshalb waren auch die Methoden aus dem Modul „Methoden“, die wir aus main aufgerufen haben, static.
Genauer, für Neugierige
Umgekehrt geht es auch: In einer static-Methode kannst du ein Objekt erzeugen und seine Methoden aufrufen. Genau das machen wir in main seit dem Anfang des Moduls.
Probier es aus
Finde den Fehler
Wähle die Zeile mit dem Fehler.
label() liest name, und name gehört zu einem konkreten Produkt. Eine static-Methode hat kein Objekt, also weiß sie nicht, wessen Namen sie nehmen soll:error: non-static variable name cannot be referenced from a static contextstatic: Die Beschriftung gehört zum Produkt, also ist sie eine Instanzmethode.Die Idee
Konstanten
Die MwSt. ist für alle Produkte 20%, und sie ändert sich nicht, während das Programm läuft. So ein Wert ist eine Konstante:
class Prices { public static final double VAT_RATE = 0.20;
public static double withVat(double price) { return price * (1 + VAT_RATE); }}
System.out.println(Prices.withVat(50));System.out.println("MwSt.: " + Prices.VAT_RATE * 100 + "%");60.0MwSt.: 20.0%static final bedeutet „der Klasse“ und „nicht änderbar“. In Java schreibt man die Namen von Konstanten mit Großbuchstaben und Unterstrichen: VAT_RATE.
Wenn jemand versucht, sie zu ändern,
Prices.VAT_RATE = 0.25;lässt sich das Programm nicht kompilieren:
error: cannot assign a value to static final variable VAT_RATEDu gewinnst doppelt: Die Zahl 0.20 steht an einer Stelle mit einem klaren Namen, und niemand kann sie aus Versehen ändern.
Genauer, für Neugierige
Manchmal ist der Wert für jedes Objekt anders, darf sich aber nach dem Erzeugen des Objekts nicht ändern. So ist die Nummer des Produkts:
private static int nextId = 1;private final int id;
public Product(String name) { this.name = name; id = nextId; nextId++;}Ein final-Feld (ohne static) wird einmal gesetzt, im Konstruktor, und ändert sich danach nicht. Der Versuch id = 5; in einer Methode lässt sich nicht kompilieren.
Probier es aus
Was fehlt?
class Calendar {
public static int MONTHS = 12;
}final: Mit static final gehört der Wert zur Klasse und ändert sich nicht.Die Idee
Wann static und wann nicht
Frag dich: „Gehört das zu einem konkreten Objekt?“
- Ja (der Kontostand des Kontos, der Name des Produkts, das Abheben von einem Konto): ein Feld oder eine Methode des Objekts, ohne
static. - Nein (die Anzahl aller Konten, die MwSt., die Summe zweier Zahlen):
static.
Ein häufiger Fehler ist, alles static zu machen, weil main static ist und der Compiler dann aufhört, sich zu beschweren. Dann teilen sich alle „Objekte“ dieselben Daten, und du bist wieder beim Problem mit den parallelen Arrays aus der ersten Lektion.
Übung
Was alle Objekte teilen
Löse die Aufgaben in deinem Editor.
1. Bestellungen. Eine Klasse Order mit Kunde und Betrag. Jede neue Bestellung bekommt die nächste Nummer aus einem statischen Zähler. Eine statische Methode getCount() gibt zurück, wie viele Bestellungen erzeugt wurden.
Order[] orders = { new Order("Maria", 45.5), new Order("Peter", 120), new Order("Elena", 18.9)};for (Order o : orders) { System.out.println(o);}System.out.println("Bestellungen: " + Order.getCount());Bestellung Nr. 1: Maria, 45.5 €Bestellung Nr. 2: Peter, 120.0 €Bestellung Nr. 3: Elena, 18.9 €Bestellungen: 32. Taschenrechner. Eine Klasse Calculator mit statischen Methoden zum Addieren, Subtrahieren und Multiplizieren ganzer Zahlen und zum Dividieren von Dezimalzahlen.
System.out.println(Calculator.add(10, 20));System.out.println(Calculator.subtract(10, 15));System.out.println(Calculator.multiply(6, 7));System.out.println(Calculator.divide(5, 2));30-5422.53. Wechselstube. Eine Klasse Converter mit Konstanten für den Kurs: 1 € = 1,08 US-Dollar und 1 € = 0,85 britische Pfund (die Kurse sind Beispiele). Statische Methoden rechnen einen Betrag in Euro in Dollar und in Pfund um. Für 20 €:
20.0 EUR = 21.6 USD20.0 EUR = 17.0 GBPWeitere Aufgaben
- Nummerierte Konten. Gib dem
Accountaus der Lektion „Kapselung“ eine Kontonummer aus einem statischen Zähler und einfinal-Feld für die Nummer. - Umrechnen in beide Richtungen. Gib
ConverterMethoden, die von Dollar und von Pfund in Euro umrechnen. Rechne 20 € in Dollar um und zurück in Euro. Bekommst du genau 20? - Ein Limit. Der Shop nimmt höchstens 3 Produkte in einem Warenkorb an. Füge dafür eine Konstante hinzu und lass die Methode zum Hinzufügen das vierte ablehnen.
Kurz gesagt
Das Modul in kurz
- Eine Klasse ist dein eigener Typ, und ein Objekt ist ein konkretes Exemplar davon, erzeugt mit
new. Die Variable zeigt auf das Objekt. Klassen und Objekte - Der Konstruktor sorgt dafür, dass das Objekt vollständig entsteht.
thisist das aktuelle Objekt. Konstruktoren und this - Instanzmethoden arbeiten mit den Feldern des Objekts.
toString()sagt, wie es als Text aussieht. Instanzmethoden privateversteckt die Felder. Von außen kommst du nur über Methoden an sie, die prüfen. Kapselungstaticist das, was die Klasse teilt: Zähler, Hilfsmethoden und Konstanten.
Daten und Regeln an einer Stelle, die niemand umgehen kann: Das ist objektorientierte Programmierung. Im nächsten Modul fangen Klassen an, Code miteinander zu teilen.
Test
Teste dich
Verwandte Lektionen
Abschnitt „Verwandte Lektionen“- Baut auf: Klassen und Objekte · Konstruktoren und this · Instanzmethoden · Kapselung
- Geht weiter in: OOP-Prinzipien · Werfen und eigene Exceptions · Reguläre Ausdrücke: Gruppen und Ersetzen · Daten in Dateien
- Aufgaben zum Thema: Klassen und Objekte