Variable / Attribut / Klassenattribut / lokale Variable

Was ist der Unterschied zwischen Variablen und Attributen?

„Variable“ ist eigentlich der allgemeinere Begriff. Auch ein Attribut ist eine Variable. Allerdings wird in der Literatur (leider) oft „Variable“ verwendet wenn nur methoden- oder blocklokale Variablen (also keine Attribute) gemeint sind. Aus dem Kontext wird das dann mehr oder weniger gut klar. Besser ist es auf jeden Fall, genau zu schreiben, was man meint. Hier eine kleine, mehr oder weniger sinnfreie Beispielklasse zur Erläuterung der Begriffe:

public class Person {

    public static int maxPersonalNummer;
    private String name;
    private String vorname;
    private int geburtsJahr;
    private final int personalNummer;

    public Person(String vorname, String name, int geburtsJahr) {
        this.name = name;
        this.vorname = vorname;
        this.geburtsJahr = geburtsJahr;
        Person.maxPersonalNummer++;
        personalNummer = Person.maxPersonalNummer;
    }

    public int getAlter() {
        int aktuellesJahr = IrgendeineKlasse.getCurrentYear;
        return aktuellesJahr - geburtsJahr;
    }
}

Attribut: Eine Variable, die Teil des Zustands eines Objekts ist. Ein Attribut wird über sein Objekt angesprochen. Aus einem Objekt heraus werden seine Attribute über „this“ angesprochen, das „this“ kann aber auch wegfallen, wenn der Bezeichner nicht durch eine methodenlokale Variable verdeckt wird. Im Beispiel sind name, vorname, geburtsJahr und personalNummer Attribute, wobei personalNummer eine Sonderrolle spielt, weil es nach der Initialisierung unveränderlich ist. Attribute werden in der Klasse für deren Exemplare deklariert, gehören aber den Exemplaren, jedes Exemplar hat sein eigenes.

Klassenattribut: Eine einer Klasse zugeordnete Variable, die nicht zu einem Exemplar der Klasse gehört, sondern zur Klasse selbst. Klassenattribute spielen in Java oft die Rolle, die in der prozeduralen Programmierung globale Variablen spielen. Ein Klassenattribut ist erkennbar am Modifikator „static“ und wird über den Namen der Klasse angesprochen. Bei Zugriffen aus derselben Klasse kann die Angabe des Klassennamens entfallen.

Methodenlokale Variable: Eine Variable, die innerhalb einer Methode deklariert ist. Eine methodenlokale Variable ist ab der Deklarationsstelle innerhalb der Methode bis zu deren Ende gültig. Im Beispiel ist aktuellesJahr eine methodenlokale Variable der Methode getAlter().

Ähnlich den lokalen Variablen sind die Parameter des Konstruktors (den man für diesen Fall als spezielle Methode begreifen kann): Die formalen Parameter einer Methode oder eines Konstruktors gelten für den Rumpf der Methode bzw. des Konstruktors. Ihnen werden beim Aufruf Kopien der Werte der aktuellen Parameter zugewiesen.

Und dann gibt es noch blocklokale Variablen. Z.B. ist in einer typischen For-Schleife

 for(int i = 0; i < whatever; i++) { // Schleifenrumpf }

die Variable i nur innerhalb der For-Schleife gültig, also in deren Schleifenkopf und im Rumpf. Betrachtet man Methoden und Konstruktoren als Blöcke (was legitim ist), so kann man methodenlokale und konstruktorlokale Variablen als Sonderfälle von blocklokalen Variablen ansehen.

Wo können unveränderliche Attribute initialisiert werden?

Frage:        Im Beispiel auf Seite 89 steht bzgl. der Zuweisung ax = 7  (Zuweisung im Konstruktor):  „Korrekt: Initialisierung im Konstruktor und nicht an der Deklarationsstelle.“  Oben im Text steht allerdings:  „Unveränderliche Variablen und Attribute müssen entweder an der Deklarationsstelle oder im umfassenden Block bzw. dem Konstruktor initialisiert werden.“ Also könnte die Zuweisung ax=7 auch an der Deklarationsstelle gemacht werden, oder?

Antwort:     Ja. Bei Attributen geht beides. Klarer wäre hier: „Unveränderliche blocklokale Variablen (incl. methoden- und konstruktorlokale Variablen) müssen an der Deklarationsstelle initialisiert werden, unveränderliche Attribute entweder an der Deklarationsstelle oder in den Konstruktoren.“

Warum darf eine Klassenmethode nur auf Klassenattribute "einfach so" zugreifen, nicht aber auf "normale" Attribute?

Die „normalen Attribute“ (= Instanzvariablen) sind zwar in der Klasse deklariert (man kann für diesen Fall eine Klasse als Bauplan für die Exemplare ansehen), aber für deren Exemplare: Jedes Exemplar hat seine eigenen Attribute. Klassenmethoden und -attribute hingegen gehören zur Klasse selbst. Sie gibt es nur einmal pro Klasse, und zwar völlig unabhängig davon, ob von dieser Klasse Exemplare überhaupt existieren. Es ergibt also keinen Sinn, aus einer Klassenmethode auf ein „normales Attribut“ zuzugreifen, ohne dass man damit das Attribut eines bestimmten Exemplars der Klasse meint und dieses Exemplar beim Zugriff auch angibt, denn die Klassenmethode gehört zur Klasse und weiß nichts von Exemplaren. Auf Klassenattribute der eigenen Klasse hingegen kann sie direkt zugreifen, ohne den Klassennamen anzugeben (so wie ein Objekt das auf seine eigenen Attribute und Methoden kann, ohne "this" anzugeben) denn die gehören ebenfalls zur Klasse und sind von Exemplaren völlig unabhängig.