Javaschubla.de - Java als erste Programmiersprache

OO05 Ein Objekt als Parameter übergeben

Wir haben schon primitive Variablen und Werte als Parameter an Methoden übergeben, nun wollen wir ein Objekt an eine Methode übergeben. Nehmen wir als Beispiel ein Angestellten-Objekt.

Die Klasse Angestellter sieht nun, nach OO04, so aus:

class Angestellter
{
  String vorname;
  String nachname;
  int alter;
  int gehalt;

  Angestellter(String v, String n, int a, int g)
  {
    vorname = v;
    nachname = n;
    alter = a;
    gehalt = g;
  }

  void erhöheGehalt(int erhöhung)
  {
    if (erhöhung <= 0)
    {
      System.err.println("Das ist aber keine Erhöhung!");
    }
    else
    {
      gehalt += erhöhung;
    }
  }

  void geburtstagFeiern()
  {
    alter++;
    System.out.println("Happy birthday " + vorname + " " + nachname + "!");
  }
}

Und Angestellten-Objekte erzeugen wir so:

    Angestellter a1 = new Angestellter("Petra", "Müller", 45, 1800);

Primitive Variablen werden "by value" übergeben, also kopiert. Wenn sie in der aufgerufenen Methode geändert werden, ändert sich an der ursprünglichen Variable nichts:

class PrimitiveUebergabe
{
  public static void main(String[] args)
  {
    int i = 5;
    plusEins(i);
    System.out.println(i); // immer noch 5
  }
 
  static void plusEins(int i)
  {
    i++;
  }
}

Objekte hingegen werden by reference übergeben, die aufgerufene Methode erhält als Parameter keine Kopie des Objekts, sondern eine Referenz (Pointer, Zeiger) auf das ursprünglich Objekt. Wenn das Objekt in der aufgerufenen Methode geändert wird, ändert es sich auch in der aufrufenden Methode.

class ObjektUebergabe
{
  public static void main(String[] args)
  {
    Angestellter a1 = new Angestellter("Petra", "Müller", 45, 1800);
    gehaltErhöhen(a1);
    System.out.println(a1.gehalt); // 1850
  }
 
  static void gehaltErhöhen(Angestellter a);
  {
    a.gehalt += 50;
  }
}

Oder doch alles by value?

Es gibt eine andere Betrachtungsweise, nach der man sagen kann, dass in Java alles by value übergeben wird, also kopiert. Und zwar wenn man die Variable (a1 bzw. a) nicht als für das Angestellten-Objekt stehend betrachtet, sondern als für die Adresse (Referenz, Pointer, Zeiger) des Angestellten-Objekts stehend. Die Adresse wird von der Variable a1 in die Variable (Parameter) a kopiert. Also wurde a1 "by value" übergeben.

Man kann es also so oder so betrachten und dann entweder sagen

Hauptsache, man weiß, was passiert - in diesem Fall also wird das Gehalt tatsächlich um 50 erhöht.

Ich bevorzuge die erste Betrachtungsweise, nach der die Variable für das Objekt steht, Objekte also by reference übergeben werden. Es gibt aber auch zwei Gründe für die zweite Betrachtungsweise, dass die Variable für die Adresse steht.

1)

class ObjektUebergabe2
{
  public static void main(String[] args)
  {
    Angestellter a1 = new Angestellter("Petra", "Müller", 45, 1800);
    gehaltErhöhen(a1);
    System.out.println(a1.gehalt); // immer noch 1800
  }
 
  static void gehaltErhöhen(Angestellter a);
  {
    a = new Angestellter(a.vorname, a.name, a.alter, a.gehalt + 50);
  }
}

Hier wird der lokalen Variable a ein neues Objekt zugewiesen. Das hat auf die Variable a1 keinen Einfluss.

Vor der Zuweisung zeigen a und a1 auf dasselbe Objekt, das sich irgendwo im Speicher befindet - genau so wie bei Strings. Deshalb ist a.gehalt dasselbe wie a1.gehalt, wenn man a.gehalt verändert, verändert sich auch a1.gehalt - es ist genau dieselbe Variable (gehalt), dieselbe Speicherstelle (die Änderung wird also nicht etwa zweimal gemacht). Bei der Zuweisung a = new Angestellter(...) wird ein neues Angestellten-Objekt erzeugt, das woanders im Speicher steht, also eine andere Adresse hat. Dann zeigen a und a1 auf unterschiedliche Objekte, sie enthalten unterschiedliche Adressen, a1.gehalt und a.gehalt sind verschieden. a.alter und a1.alter haben zwar den gleichen Wert, aber sie hängen nicht mehr zusammen, verändert man eines, verändert sich nicht das andere.

2) Beim Vergleichen.

Wie bei Strings wird beim Vergleichen mit == nicht der Inhalt, sondern die Adresse verglichen.

class ObjekteVergleichen
{
  public static void main(String[] args)
  {
    Angestellter a1 = new Angestellter("Petra", "Müller", 45, 1800);
    Angestellter a2 = new Angestellter("Petra", "Müller", 45, 1800);
    System.out.println(a1==a2); // gibt false aus
  }
}

a1 und a2 zeigen auf zwei Objekte, die zwar den gleichen Inhalt haben (die gleichen Werte für die Attribute vorname, name, alter und gehalt), aber es ist nicht dasselbe Objekt. Wenn man eines verändern würde, würde sich das andere nicht verändern. Sie stehen nicht an derselben Adresse, also ist a1==a2 false.

Zu einer equals-Methode für Angestellter kommen wir als nächstes, in OO06.

Bei der Übergabe einer Variable an eine Methode ist also alles genau so, als würde man ihren Wert einer Variablen in derselben Methode zuweisen.

class PrimitiveUndObjekte
{
  public static void main(String[] args)
  {
    int i = 3;
    int j = i;
    j = 2;
    System.out.println(i); // ist immer noch 3

    Angestellter a1 = new Angestellter("Petra", "Müller", 45, 1800);
    Angestellter a2 = a1;
    a2.gehalt = 1900;
    System.out.println(a1.gehalt); // 1900
    a2 = new Angestellter("Leszek", "Wawrzyniak", 23, 1300);
    System.out.println(a1.vorname); // immer noch Petra
  }
}

In der nächsten Lektion schreiben wir eine equals-Methode für die Klasse Angestellter.