W3docs

Java Klassenattribute (Felder)

Instanzfelder in einer Java-Klasse deklarieren, Initialwerte setzen und über Objekte darauf zugreifen.

Die Attribute einer Klasse sind die darin deklarierten Variablen — die Daten, die jedes Objekt trägt. Die meisten Autoren nennen sie Felder (so auch die Java Language Specification), und „Attribut" ist der allgemeinere OOP-Begriff; beide meinen dasselbe. In diesem Kapitel geht es darum, wie man sie deklariert, welche Anfangswerte sie haben und wie man sie von außerhalb der Klasse lesen und schreiben kann.

Ein Feld deklarieren

Ein Feld sieht wie eine lokale Variable aus, befindet sich jedoch im Klassenrumpf und nicht innerhalb einer Methode:

public class Book {
  String title;
  String author;
  int    pages;
  boolean inPrint;
}

Jede Instanz von Book erhält eine eigene Kopie dieser vier Felder. Zwei Bücher haben zwei separate title-Strings, zwei separate pages-Ints usw. Sie leben so lange wie das Objekt selbst — bis es keine Referenz mehr darauf gibt.

Standardwerte

Wenn ein Feld nicht initialisiert wird, übernimmt Java die Initialisierung. Die Standardwerte hängen vom Typ ab:

TypStandard
byte, short, int, long0
float, double0.0
char'�' (das Nullzeichen, Codepunkt 0 — kein Leerzeichen)
booleanfalse
beliebiger Objekttypnull
Book b = new Book();
System.out.println(b.title);    // null
System.out.println(b.pages);    // 0
System.out.println(b.inPrint);  // false

Dies ist ein wesentlicher Unterschied zwischen Feldern und lokalen Variablen innerhalb von Methoden — lokale Variablen erhalten keinen Standardwert, und der Compiler verweigert das Lesen einer Variable, bevor ihr ein Wert zugewiesen wurde. Felder starten immer mit irgendetwas.

Inline-Initialisierer

Ein Feld kann direkt bei der Deklaration einen Wert erhalten:

public class Book {
  String title   = "Untitled";
  int    pages   = 0;
  boolean inPrint = true;
}

Der Initialisierer wird einmal pro Objekt ausgeführt, wenn dieses Objekt erstellt wird. Er läuft in Deklarationsreihenfolge, vor dem Konstruktorrumpf. Wenn ein Feld eine komplexere Initialisierung benötigt, ist das Aufgabe des Konstruktors.

Felder lesen und schreiben

Man verwendet <reference>.<field> von außen und einfach <fieldName> (oder this.<fieldName>) von innerhalb der Klasse selbst:

Book b = new Book();
b.title = "Effective Java";    // write
String t = b.title;            // read

Innerhalb der Klasse:

public class Book {
  String title;
  void rename(String t) {
    title = t;             // same as this.title = t;
  }
}

Das Kapitel zum this-Schlüsselwort erklärt, wann der explizite this.-Qualifizierer benötigt wird und wann nicht.

Namenskonventionen

Java-Feldnamen werden in lowerCamelCase geschrieben:

String firstName;       // good
String first_name;      // not Java style
String FirstName;       // looks like a class

Boolean-Felder werden häufig mit den Präfixen is oder has benannt (isPublished, hasIndex), damit sich Aufrufstellen natürlich lesen: if (book.isPublished). Konstanten — Felder, die sich nicht ändern — werden in UPPER_SNAKE_CASE geschrieben und mit static final gekennzeichnet; das wird in den Kapiteln zu static und final behandelt.

Instanzfelder vs. Klassenfelder

Standardmäßig gehören Felder zu jeder Instanz — jedes Objekt hat eine eigene Kopie. Mit static gehört das Feld zur Klasse selbst; es gibt genau eine Kopie, die von allen Instanzen gemeinsam genutzt wird:

public class Counter {
  int count;            // instance — each Counter has its own
  static int total;     // class    — one shared by all Counters
}

Counter a = new Counter();
Counter b = new Counter();
a.count++;   b.count++;   b.count++;
Counter.total++;

System.out.println(a.count);          // 1
System.out.println(b.count);          // 2
System.out.println(Counter.total);    // 1, accessed through the class

Die vollständige Erklärung findet sich im Kapitel zu static; für den Moment kann man davon ausgehen, dass jedes Feld ein Instanzfeld ist, sofern es nicht ausdrücklich mit static markiert ist.

Öffentliche Felder sind meist ein Fehler

Java erlaubt es, public String title; zu schreiben und externem Code direkten Schreibzugriff zu geben. In der Praxis macht man das fast nie. Sobald ein Feld public ist, verliert man die Möglichkeit, Schreibvorgänge zu validieren, den Typ später zu ändern oder Lesevorgänge mit Logik zu versehen — jeder, der das Feld berührt, ist an seine aktuelle Darstellung gebunden.

Das Standardmuster ist, Felder als private zu markieren und stattdessen Getter und Setter bereitzustellen:

public class Book {
  private String title;

  public String getTitle()          { return title; }
  public void   setTitle(String t)  { this.title = t; }
}

Das ist Kapselung. Die Kapitel zu Kapselung und Gettern & Settern beschreiben das vollständige Muster. In frühen Beispielen werden Felder der Übersichtlichkeit halber direkt gezeigt, aber echter Java-Code hält sie privat.

Felder speichern Referenzen, keine Objekte

Wenn der Typ eines Feldes eine Klasse ist (kein primitiver Typ), ist das Feld eine Referenz. Zwei Objekte können dasselbe zugrunde liegende Objekt über ihre Felder gemeinsam nutzen:

public class Author { String name; }
public class Book   { Author author; }

Author a = new Author();
a.name = "Joshua Bloch";

Book b1 = new Book();   b1.author = a;
Book b2 = new Book();   b2.author = a;     // same Author object

a.name = "J. Bloch";
System.out.println(b1.author.name);   // J. Bloch
System.out.println(b2.author.name);   // J. Bloch

Es gelten dieselben Hinweise wie im vorherigen Kapitel: Manchmal ist das beabsichtigt, manchmal ist es ein Fehler. Wenn ein Book seinen eigenen Author haben soll, würde man jedem new Author() zuweisen.

Ein ausgearbeitetes Beispiel

java— editable, runs on the server

Was kommt als Nächstes

Felder sind der Zustand eines Objekts. Die andere Hälfte — sein Verhalten — steckt in den Methoden, die in der Klasse deklariert sind. Das nächste Kapitel über Klassenmethoden zeigt, wie man Methoden an Instanzen bindet und wie diese auf die soeben definierten Felder zugreifen.

Übungen

Übung
Ein Instanzfeld vom Typ int wird deklariert, aber nie zugewiesen. Welchen Wert hat es, wenn man es über ein neu erstelltes Objekt liest?
Ein Instanzfeld vom Typ int wird deklariert, aber nie zugewiesen. Welchen Wert hat es, wenn man es über ein neu erstelltes Objekt liest?
Was this page helpful?