Javaschubla.de - Java als erste Programmiersprache

OO07 Kapselung mit Zugriffsmodifizierern, private Attribute

Betrachten wir unsere Klasse Angestellter, ohne die equals-Methode der Übersicht halber:

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 + "!");
  }
}

Wir haben eine Methode, mit der man das Gehalt erhöhen kann, und keine, mit der man es senken kann - und genau so wollen wir es haben, sonst ist die Gewerkschaft sauer. Das Alter kann man mit geburtstagFeiern um ein Jahr erhöhen, nicht um mehrere auf einmal, nicht senken, nicht auf einen beliebigen Wert setzen. Außerdem gibt es beim Alter erhöhen eine Nebenwirkung - hier wird einfach "Happy birthday" und der name ausgegeben, in echt könnte z.B. eine Geburtstagskarte von der Firma verschickt werden.

Aber jemand, der die Klasse benutzt, also z.B. der Programmierer der Klasse AngestelltenVerwaltung, könnte einfach direkt auf die Attribute zugreifen. a.erhöheGehalt(-50) geht nicht? Dann macht er halt a.gehalt -= 50; a.einJahrJüngerMachen() gibt es nicht? Dann macht er einfach a.alter -= 1; Das wollen wir nun unterbinden. Dazu machen wir die Attribute einfach private, dann können andere Klassen nicht mehr auf sie zugreifen.

class Angestellter
{
  private String vorname;
  private String nachname;
  private int alter;
  private 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 + "!");
  }
}

Jetzt können andere Klassen die Attribute aber auch nicht mehr lesen! Das wollen wir natürlich nicht. Wir schreiben für jedes Attribut eine get-Methode.

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

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

  String getVorname()
  {
    return vorname;
  }

  String getNachname()
  {
    return nachname;
  }

  int getAlter()
  {
    return alter;
  }

  int getGehalt()
  {
    return gehalt;
  }

  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 + "!");
  }
}

Z.B. in der Klasse AngestelltenVerwaltung schreiben wir nun statt a.alter a.getAlter() usw.

Wer seine Javaprogramme in einer IDE, also einer integrierten Entwicklungsumgebung wie z.B. Eclipse, schreibt, kann sich für alle seine Attribute getter (und auch setter) mit ein paar Mausklicks generieren lassen.

Es geht nicht wirklich darum, bösartige Schreiber anderer Klassen davon abzuhalten, die Attribute auf andere Weise zu ändern, als dies erlaubt ist, sondern den versehentlichen direkten Zugriff zu verhindern und Fehler abzufangen. Der Programmierer der Klasse AngestelltenVerwaltung weiß vermutlich auch, dass das Gehalt nur erhöht, nicht gesenkt werden darf. Aber wenn er das Gehalt nicht um einen festen Betrag erhöht (wie in a.gehalt += 50), sondern den Erhöhungsbetrag auf komplizierte Weise berechnet (etwa über Alter, Betriebszugehörigkeit, erreichte Ziele und diesjährigem Unternehmensgewinn), könnte es sein, dass etwas Negatives herauskommt und er es nicht bemerkt. Wenn er die Methode gehaltErhöhen() aufruft, wird das überprüft. Wenn er a.gehalt += ergebnisKomplizierterBerechnung benutzt, muss er jedes Mal selbst überprüfen, dass der Betrag positiv ist. Er könnte das vergessen. Genau so wie das Anzeigen des Geburtstagsgrußes (bzw. Versenden der Geburtstagskarte), wenn er a.alter++ benutzt statt a.geburtstagFeiern().


Übung

Füge eine Methode setGehalt(int neuesGehalt) hinzu. Sie soll eine Fehlermeldung ausgeben, wenn das neue Gehalt unzulässig ist.


Auf private Attribute einer anderen Instanz derselben Klasse zugreifen

Noch einmal zur equals-Methode:

  public boolean equals(Angestellter a)
  {
    return a.vorname.equals(vorname) && a.nachname.equals(nachname) && a.alter == alter && a.gehalt == gehalt;
  }

Funktioniert das jetzt überhaupt noch? Können wir auf a.vorname etc. zugreifen? Es ist ja private und es geht um ein anderes Objekt, auch wenn es vom selben Typ ist (eine andere Instanz derselben Klasse). Die Antwort ist ja: Verschiedene Objekte desselben Typs können gegenseitig auf ihre privaten Attribute und Methoden zugreifen.


In der nächsten Lektion wird die Einführung in die Objektorientierung fortgesetzt, und zwar mit privaten Methoden.