W3docs

Java-Klassen und Objekte

Definiere eine Java-Klasse und erstelle daraus Objekte (Instanzen) — die Grundlage von Javas objektorientiertem Modell.

Eine Klasse ist eine Definition; ein Objekt ist eine Instanz dieser Definition, die zur Laufzeit existiert. Die Klasse beschreibt wie ein Hund aussieht und was er tun kann; ein Objekt ist Rex, ein konkreter Hund, der im Speicher lebt, während dein Programm läuft. Alles Folgende baut auf dieser Unterscheidung auf.

Eine Klasse definieren

Eine Klassendefinition befindet sich in einer eigenen .java-Datei, die nach der Klasse benannt ist. Der Rumpf enthält Felder (die Daten, die jede Instanz trägt) und Methoden (das Verhalten, das jede Instanz ausführen kann).

public class Dog {
  String name;
  int    age;

  void describe() {
    System.out.println(name + ", age " + age);
  }
}

Dies deklariert einen Typ. Es werden noch keine Hunde erstellt — genau so, wie das Schreiben von int keine Ganzzahl erzeugt.

Ein Objekt mit new erstellen

Das Schlüsselwort new weist die JVM an, Speicherplatz für eine Instanz zu reservieren und eine Referenz darauf zurückzugeben:

Dog d = new Dog();

Dabei geschehen drei Dinge:

  1. Zuteilung. Die JVM findet genug Heap-Speicher für einen Dog.
  2. Standardinitialisierung. Jedes Feld erhält einen Standardwert — null für Objekte, 0 für ints, false für booleans.
  3. Konstruktoraufruf. Die () rufen einen Konstruktor auf. Wir haben keinen geschrieben, also stellt Java einen Standard-Konstruktor ohne Argumente bereit, der nichts Zusätzliches tut. Das nächste Kapitel über Konstruktoren behandelt das Schreiben eigener Konstruktoren.

Danach enthält d eine Referenz — einen kleinen Wert, der auf das Heap-Objekt zeigt. Das Objekt selbst ist das größere Ding auf dem Heap.

Felder lesen und schreiben

Du erreichst ein Feld, indem du <reference>.<field> schreibst:

d.name = "Rex";
d.age  = 3;
System.out.println(d.name);   // Rex

Der Feldzugriff funktioniert auch beim Aufrufen von Methoden:

d.describe();    // Rex, age 3

Der Punkt ist in beiden Fällen gleich; ob die rechte Seite ein Feld oder eine Methode ist, hängt davon ab, was folgt.

Referenzen sind nicht das Objekt

Dies ist der wichtigste Satz in diesem Kapitel: Eine Variable eines Klassentyps enthält eine Referenz, nicht das Objekt selbst.

Dog a = new Dog();
a.name = "Rex";

Dog b = a;           // copies the REFERENCE, not the dog
b.name = "Buddy";

System.out.println(a.name);   // Buddy

a und b zeigen auf dasselbe Heap-Objekt, also ist eine Änderung über das eine durch das andere sichtbar. Vergleiche mit primitiven Typen:

int x = 5;
int y = x;       // copies the value
y = 9;
System.out.println(x);    // still 5

x und y sind unabhängig — primitive Typen werden per Wert kopiert. Das Kapitel über pass-by-value geht tiefer darauf ein, was das für Methodenargumente bedeutet.

null und NullPointerException

Eine Referenzvariable kann null sein, was bedeutet „zeigt auf kein Objekt":

Dog d = null;
d.describe();    // NullPointerException

null erhältst du, wenn du nie ein Objekt zugewiesen hast oder wenn ein Feld eines Objekttyps nie explizit initialisiert wurde. Das Dereferenzieren von null (das Schreiben von d.something, wenn d == null) wirft zur Laufzeit eine NullPointerException. Code zu schreiben, der bei null nicht abstürzt, ist die halbe Kunst in der praktischen Java-Entwicklung.

Warnung
NullPointerException ist ein Laufzeitfehler, kein Kompilierfehler — der Code kompiliert problemlos und schlägt erst fehl, wenn diese Zeile tatsächlich ausgeführt wird. Die Lösung ist sicherzustellen, dass die Variable auf ein echtes Objekt zeigt (d = new Dog();) oder vor dem Dereferenzieren eine Prüfung einzubauen (if (d != null) d.describe();).

Objekte vergleichen: == vs equals

Bei Referenzen fragt ==: „Zeigen diese beiden Variablen auf dasselbe Objekt?":

Dog a = new Dog();
Dog b = new Dog();
Dog c = a;

System.out.println(a == b);   // false — different objects
System.out.println(a == c);   // true  — same object

Wenn du den Inhalt zweier Objekte vergleichen möchtest, rufst du stattdessen eine equals-Methode auf — jede Klasse erbt eine Standardimplementierung von Object, aber der Standard führt lediglich Referenzvergleiche durch. Du überschreibst equals, um das gewünschte Verhalten zu definieren; siehe das Kapitel equals & hashCode weiter hinten in diesem Teil.

Eine Datei, viele Objekte

Eine einzelne Klassendefinition unterstützt eine unbegrenzte Anzahl von Instanzen. Sie teilen alle das Layout, aber jede hat ihren eigenen Zustand:

Dog rex   = new Dog();   rex.name   = "Rex";   rex.age   = 3;
Dog molly = new Dog();   molly.name = "Molly"; molly.age = 7;

rex.describe();     // Rex, age 3
molly.describe();   // Molly, age 7

Eine Methode wie describe liest von this — dem Objekt, auf dem sie aufgerufen wurde — daher gibt derselbe Code je nach aufgerufener Instanz unterschiedliche Ausgaben aus.

Wo Klassen leben

Eine .java-Datei, die public class Dog deklariert, muss Dog.java heißen. Du kannst nicht-öffentliche Klassen in derselben Datei haben, aber nur eine public-Klasse pro Datei, und ihr Name muss mit dem Dateinamen übereinstimmen. Für kleine Programme in diesem Kapitel platzieren wir Hilfsklassen häufig mit static-verschachtelten Klassen in derselben Datei wie main, um das Beispiel auf eine Datei zu beschränken.

Ein ausgearbeitetes Beispiel

java— editable, runs on the server

Wie geht es weiter?

Du kannst eine Klasse deklarieren und instanziieren, aber bisher war das einzige Feld, das du geschrieben hast, „beliebiger Wert erlaubt." Das nächste Kapitel über Klassenattribute behandelt Felder ausführlich — Deklaration, Standardwerte, Instanz- vs. Klassenbereich und die Konventionen, die Java-Code befolgt.

Übungen

Übung
Gegeben Dog a = new Dog(); Dog b = a; b.name = 'Rex'; — was gibt System.out.println(a.name) aus?
Gegeben Dog a = new Dog(); Dog b = a; b.name = 'Rex'; — was gibt System.out.println(a.name) aus?
Was this page helpful?