III Klassen und Vererbung

15 Konstruktoren, Attribute und Methoden
15.1 Die Klasse Punkt Version 1
   
Klasse und Objekte Wenn wir von einem Punkt P in einer Ebene sprechen, sprechen wir von einer Klasse. Wenn wir vom P1(2|3) sprechen, meinen wir eine Instanz von P also ein Objekt. (vgl. dazu 3.1 Klasse und Objekt)

Wir modellieren die Klasse in Java:  Objekte dieser Klasse sollen erzeugt, die Punkte verschoben und am Ursprung gespiegelt werden können. Standardmäßig wird beim Erzeugen eines nicht weiter spezifizierten Punktes der Punkt (0|0) erzeugt werden. Man soll aber auch jeden beliebigen Punkt P(x0|y0) der Zahlenebene gezielt erzeugen können. Mit den  Punkten wollen wir aber auch operieren können, d.h. sie z.B. in dem Koordinatensystem verschieben oder am Ursprung spiegeln können. Um eine optische Darstellung der Punkte scheren wir uns nicht. In UML hat die Klasse dann die Darstellung:


Abb.15.1.1 UML-Darstellung der Klasse Punkt


 

Implementierung der Klasse

Download:
Punkt.java

class Punkt {
  public int x,y;
  public Punkt() {
    x=0;
    y=0;
  }
  public Punkt(int xNeu, int yNeu) {
    x = xNeu;
    y = yNeu;
  }
  public void verschiebe(int dx, int dy) {
    x += dx;
    y += dy;
  }
  public void spiegleAmUrsprung() {
    x = -x;
    y = -y;
  }
}

Attribute Die Attribute der Klasse sind x und y, gemeint sind damit die x- und y-Koordinate eines Punktes. Diese Attribute haben für jedes Objekt, das wir nach dem Bauplan dieser Klasse anlegen konkrete, individuelle Werte.
 
Konstruktoren Die Konstruktoren einer Klasse dienen dazu, Objekte von ihr zu erzeugen. Wir erkennen sie daran, dass sie wie Methoden aufgebaut sind, aber keinen Rückgabewert, nicht einmal void, besitzen. Weiter haben die Konstruktoren den gleichen Namen wie ihre Klasse.
Wenn man eine Klasse schreibt, und keinen Konstruktor implementiert, so besitzt sie automatisch den sog. Standardkonstruktor. In unserem Fall wäre dies
Punkt(){};

Der Kompiler würde ihn automatisch hinzufügen. Da zwischen den geschweiften Klammern kein weiterer Text steht, kann man mit ihm zwar Objekte anlegen, diese haben aber noch keine Eigenschaften.1) Im Falle unseres Punktes macht das wenig Sinn. Wenn wir wollen, dass die Koordinaten des Punktes, der mit dem Standardkonstruktor erzeugt wird, immer 0 sind, der Standardkonstruktor also immer den Punkt P(0|0) erzeugt, so überschreiben wir den implizit vorhanden Konstruktor durch:

public Punkt() {
   x = 0;
   y = 0;
}

Große Flexibilität erreichen wir dadurch, dass Java erlaubt für eine Klasse mehrere Konstruktoren zu implementieren. Es kann Sinn machen, z.B. auch einen Punkte zu erzeugen, deren Koordinaten vor dem Erzeugen berechnet wurden. In diesem Fall wäre folgender Konstruktor sinnvoll:

public Punkt(int xNeu, int yNeu) {
  x = xNeu;
  y = yNeu;
}

Natürlich tragen beide Konstruktoren  den gleichen Bezeichner. Damit ein Kompiler die beiden Konstruktoren unterscheiden kann, müssen sie sich in der Signatur unterscheiden., die Parameterliste müssen also unterschiedlich viele Parameter haben oder, wenn die Anzahl der Parameter bei beiden gleich ist, müssen sie sich mindestens im Typ einer Variablen in der Poarameterliste unterscheiden.
 

Methoden Über die Implementierung der Methoden in der Klasse Punkt brauchen wir nicht mehr viel Worte verlieren. Wie das geht, haben wir schon in der Klasse Mathematik gesehen. Allerdings liefern die Methoden keinen Wert an den Aufrufer zurück, weshalb sie als Rückgabewert void erhalten. Und ein weiterer wesentlicher Unterschied, sie sind nicht statisch, d.h. sie sind nicht an die Klasse sondern an ein Objekt 'gebunden'. Wir werden diesen Unterschied gleich beim Aufruf der Methoden erkennen.

Um unsere Klasse Punkt in ihrer Funktionalität zu testen, implementieren wir ein kleines Testprogramm. Der Quellkode ist selbsterklärend.
 
Download:
PunktDemo.java
Ein Demo- oder Testprogramm dient zum überprüfen der Konstruktoren und Methoden einer Fachklasse. Sie schreibt man in der Regel als kleine Applikationsprogramme ohne grafische Oberfläche. Das letztere bleibt der sog. GUI-Klasse (Grafical User Interface) vorbehalten, mit denen wir uns in Kap 19 beschäftigen werden. Der Quelltext zum Demoprogramm:
import info1.*;
public class PunktDemo{
  public static void main(String[] args){
    int x,y;
    System.out.print("x-Wert: ");
    x = Console.in.readInt();
    System.out.print("y-Wert: ");
    y = Console.in.readInt();

    Punkt p1 = new Punkt();
    Punkt p2 = new Punkt(x,y);
    
    System.out.println("P1(" + p1.x +"/" + p1.y +")");
    System.out.println("P2(" + p2.x +"/" + p2.y +")");

    p1.verschiebe(2,5);
    p2.spiegleAmUrsprung();
    
    System.out.println("P1 ist um 2 in x- und 
                         5 in y-Richtung verschoben");
    System.out.println("P1(" + p1.x +"/" + p1.y +")");
    System.out.println("P2 ist am Ursprung gespiegelt");
    System.out.println("P2(" + p2.x +"/" + p2.y +")");
    
  }
}
x-Wert: 4
y-Wert: 4
P1(0/0)
P2(4/4)
P1 ist um 2 in x- und 5 in y-Richtung verschoben
P1(2/5)
P2 ist am Ursprung gespiegelt
P2(-4/-4)
Ausgabe Nachdem x- und y-Wert eines Punktes eingelesen sind, wird ein Punkt mit dem Standardwerten (0/0) und ein weiterer mit den eingegeben Werten, also (4/4) erzeugt und als p1 und p2 angezeigt. p1 wird verschoben und p2 am Ursprung gespiegelt. Danach werden die Punkte noch einmal ausgegeben.
 
Bemerkungen zum Quellkode Wir erkennen, wie man Instanzen der Klasse Punkt deklariert und sie dann auch erzeugt: Zunächst nennt man den Namen der Klasse von der man ein Objekt anlegen möchte.  Es folgt der Name, den die Instanz tragen soll, also p1 bzw. p2. Folgten jetzt Semikola, so wären die Objekte deklariert aber noch nicht instanziiert, Objekte selbst sind somit noch nicht angelegt. Die geschieht unter Verwendung des new-Operators. Dieser benutzt den Konstruktor, um die eigentliche Erzeugung, auch Instanziierung genannt, vorzunehmen. In unserem Beispiel kommen beide Konstruktoren zum Einsatz.

Wie man auf die Koordinaten der Objekte zugreift, erkennt man in den Ausgaben. So liefert p1.x die x-Koordinate des Objektes p1  und p2.y die y-Koordinate des Objektes p2. Es handelt sich in beiden Fällen um einen direkten, lesenden Zugriff auf die Attribute der Objekte p1 und p2. Ein entsprechend direkter schreibende Zugriff sieht so aus:

p1.y = 4;

Damit hat man den y-Wert des Objektes p1 direkt geändert. Diese direkte Zugriffe auf Attribute eines Objektes versucht man in aller Regel zu vermeiden, ja zu verhindern. Direkte Zugriffe auf Objektattribute widersprechen nämlich dem Prinzip des 'Information hiding's.
 

Fußnoten  

1)

Tatsächlich hat die mit dem 'leeren' Standardkonstruktor erzeugte Klasse schon Eingenschaften. Denn jede Klasse erbt von der Klasse Object und damit von ihr z.B. die  Methoden clone() oder toString(). Wir werden im Laufe des Kurses mehr davon erfahren. [zurück]
 
zu 15.2 Kapselung
zur Startseite www.pohlig.de (C) MPohlig 2005