Praktische Informatik 1


Abstrakte Klassen, Interfaces, generische Typen



Yüklə 3,49 Mb.
səhifə22/25
tarix08.08.2018
ölçüsü3,49 Mb.
#61957
1   ...   17   18   19   20   21   22   23   24   25

9.2 Abstrakte Klassen, Interfaces, generische Typen


Abstrakte Klassen

Abstrakte Klassen sind solche, die noch nicht „fertig“ sind: sie enthalten Methoden ohne Implementierung. Beispiel:



abstract class Figur {

protected int x, y;

public void setzeX(int xNeu) {

x = xNeu;

}

public abstract float berechneFlaeche();

}

Für abstrakte Klassen ist keine Instanzenbildung erlaubt; allerdings können Unterklassen die abstrakte Klasse erweitern und die abstrakten Methoden konkretisieren.


Interfaces

Ein Interface ist das Java-Äquivalent zur Signatur eines abstrakten Datentyps. Es besteht nur aus den Köpfen der Methoden, enthält keine Datenfelder oder Algorithmen (aber auch keine algebraischen Gesetze). Eingeleitet werden Interfaces mit dem Schlüsselwort interface: Beispiel:



public interface StackInterface {

public boolean isempty();

public void push(char x);

public char top();

public void pop();

}

Die implementierende Klasse referenziert dann das Interface:



class Stack implements StackInterface { ... }
Interfaces sind gut geeignet, um Benutzungsschnittstellen von Klassen noch vor der eigentlichen Implementierung festzulegen. Von einem Interface können keine Instanzen gebildet werden (da ja keine Methodenrümpfe und Datenfelder vorliegen). Allerdings kann der Compiler die Konsistenz einer Benutzung der Klasse sowie die Konsistenz einer Implementierung des Interfaces mit der Definition überprüfen. Eine Variable, die als Typ das Interface hat, darf als Wert Objekte aller implementierenden Klassen haben. Ein wesentlicher Unterschied zwischen abstrakten Klassen und Interfaces besteht darin, dass eine Klasse mehrere Interfaces implementieren kann (sogenannte Mehrfachvererbung).
Generische Typen

Generische Typen realisieren da Konzept der parametrisierten abstrakten Datentypen. Es ist möglich, einer Klasse einen Typ als Parameter mitzugeben:



class Tupel {

private T first;

private T second;
public Tupel(T fst, T scd) {

first = fst;

second = scd;

}
public T getFirst() {



return first;

}
public T getSecond() {



return second;

}

}



Der Zugriff erfolgt dann wie folgt:

pi = new Pair (17, 24);

ps = new Pair ("Hallo", "World");

Allerdings ist das Konzept in Java nur eingeschränkt nutzbar, da z.B. keine Felder über generischen Typen gebildet werden können.



9.3 Fehler, Ausnahmen, Zusicherungen


Ausnahmen

Eine typische Situation beim Programmieren ist der Entwurf von Klassenbibliotheken für (spätere) Anwendungen. Hier muss man beständig mit unzulässige Eingaben rechnen (z.B. top(empty()), Division durch Null, usw.). Es erhebt sich die Frage, wie man mit solchen unzulässigen Eingabewerten umgehen sollte. Eine Möglichkeit besteht darin, die unzulässige Eingabe zu ignorieren und einen Standardwert zurückgeben. (z.B. x/0 = 0). Dies hat mehrere Nachteile: Der Definitionsbereich der Funktionen wird unzulässig erweitert, der Anwender der Klasse bemerkt seinen FDehler nicht und der Fehler wird unkalkulierbar verschleppt. Besser ist es, das Programm mit einer Fehlermeldung abzubrechen („lieber ein Ende mit Schrecken als ein Schrecken ohne Ende“). Die dritte Möglichkeit besteht darin, zu jeder Methode einen zusätzlichen boole’schen Ergebniswert („ok“) einzuführen, der auf true gesetzt wird wenn der Methodenaufruf fehlerfrei war. Diese Methode erfordert gegebenenfalls erheblichen zusätzlichen Schreibaufwand, wird aber z.B. in der Programmiersprache C praktiziert. In Java besteht die Lösung im „Aufwerfen“ (throw) einer Ausnahmesituation. Das „Abfangen“ (catch) der Ausnahmesituation liegt in der Verantwortung des Aufrufers; wenn er sich nicht darum kümmert, wird die Ausnahmesituation „nach oben weitergereicht“. Wenn sich niemand um den Fehler kümmert, bricht das Programm ab. Dadurch ist es möglich, gewisse Fehler auf der entsprechenden Programmebene kontrolliert zu behandeln, Debugging-Informationen auszugeben, oder das Programm sogar unter Umständen fortzusetzen.


public class Ausnahmebehandlung {

static void f() throws Exception {

Exception e = new Exception("Fehler1");



if (1==1) throw e;

}

public static void main(String[] args) {

// …

System.out.println("vor Aufruf");



try {

f();

} catch (Exception x) {

System.out.println (x + " ist aufgetreten");

}

// …



}

}
Achtung: Ausnahmesituationen gehören zur Signatur der Methode! Dies bedeutet, dass Ausnahmesituationen in Java „Bürger erster Klasse“ sind. Eine Ausnahmesituation ist ein Objekt der Klasse Exception. Das bedeutet, es gibt Konstruktoren ohne und mit Argument (String). Das Werfen einer Ausnahmesituation (throw) bewirkt die Beendigung der Methode und die Rückkehr zur Aufrufstelle. Aufruf einer Methode, die eine Ausnahmesituation werfen kann, ist nur in einem try-Block möglich; das Auftreten der Ausnahmesituation wird von nachfolgenden Exception Handlern überwacht. Der erste Exception Handler, dessen Parameter-Typ mit dem Typ der geworfenen Exception übereinstimmt, wird ausgeführt, und nach Beendigung wird des Exception Handlers wird das Programm normal fortgesetzt. Auf diese Weise ist es möglich, für jede mögliche Ausnahmesituation eine dezidierte Fehlerbehandlung anzustoßen. Jede Ausnahme muss behandelt oder weitergereicht werden (Ausnahme folgt), d.h., der Compiler zwingt den Programmierer, sich über die notwendigen Maßnahmen beim Eintreten der Ausnahmesituation Gedanken zu machen.


f();//geht nicht!

static void g() throws Exception {

f();

}

Exception-Hierarchie




  • Basisklasse aller Ausnahmen ist Throwable

  • Davon abgeleitet sind
    Exception und Error

    • Konvention: Exception für behebbare,
      Error für nicht vom Anwender
      behebbare Ursachen

    • Von Exception werden u.a. IOException und RuntimeException abgeleitet

    • RuntimeException und davon abgeleitete Klassen müssen nicht behandelt werden

Syntax
try {

// Anweisungen die Ausnahmen werfen könnten

} catch(Typ1 Objekt1) {

// Anweisungen für Ausnahme1

} catch(Typ2 Objekt2) {

// Anweisungen für Ausnahme2

} finally {

// Anweisungen für Endbehandlung

}
Es ist natürlich möglich, eigene Ausnahmen zu definieren:


static class MyException1 extends Exception{}

static class MyException2 extends Exception{}

public class Ausnahmebehandlung {

static void f() throws MyException1, MyException2 {

if (1==1) throw new MyException1();

else throw new MyException2();

}

public static void main(String[] args) {

System.out.println("vor Aufruf");

try {

f();

} catch (MyException1 x) {

System.out.println (x+" - Handler1");

} catch (MyException2 x) {

System.out.println (" Handler2: " + x);

}

finally {System.out.println("Finally!");}

};

}
Hier noch eine allgemeine Anmerkung zu Ausnahmen: Ausnahmen sollten NICHT zur Ablaufkontrolle missbraucht werden! Ausnahmen von dieser Regel sind möglich und zulässig (z.B. bei Benutzereingaben). Als Beispiel verfeinern wir unser Programm zum Einlesen einer natürlichen Zahl (größer Null).


import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

public class ZahlEingabe {

public static void main(String[] args) {

int i = 0;

System.out.println ("Bitte Zahl eingeben!");



while (i <= 0){

BufferedReader inputReader =



new BufferedReader(new InputStreamReader(System.in));

String eingabeZeile = "";



try {

eingabeZeile = inputReader.readLine();

i = Integer.parseInt (eingabeZeile);

if (i<=0) {

System.out.println ("Bitte Zahl größer Null eingeben!");}

}

catch (NumberFormatException e){

System.out.println ("Not a Number");}



catch (IOException e){

System.out.println ("I/O Exception!");}

}

System.out.println ("Eingegeben: " + i);



}

}
Zusicherungen

Zusicherungen (Assertions) sind boole‘sche Ausdrücke, die dazu dienen, die Sicherheit beim Programmieren zu erhöhen. Sie können bei der Entwicklung von Programmen helfen, Irrtümer und Missverständnisse zu vermeiden. Eingeleitet werden Zusicherungen durch das Schlüsselwort

assert expr;

oder auch



assert expr : expr;
Beispiel für eine Zusicherung:

assert (iSemantik: Während des Ablaufs des Programms wird geprüft, ob die Zusicherung eingehalten ist. Falls nicht, wird eine Ausnahme geworfen (bzw. der Ausdruck an die Ausnahme übergeben). Verwendung finden Zusicherungen unter anderem als Vor- und Nachbedingungen von Methoden (z.B. beim Aufruf von pop(x) wird zugesichert, daß !isEmpty(x)). Zusicherungen sind, wenn sie richtig eingesetzt werden, eine effiziente Methode zur Entwicklung und zum Debuggen von Programmen.

Bei der Ausführung verlangsamt die Auswertung einer Zusicherung natürlich das Programm. Daher können Zusicherungen in der Java-Laufzeitumgebung ein- und ausgeschaltet werden:

Argument: -enableassertions oder –ea

Wenn die Zusicherungsauswertung ausgeschaltet ist, können Zusicherungen als eine Art Kommentar betrachtet werden.




Yüklə 3,49 Mb.

Dostları ilə paylaş:
1   ...   17   18   19   20   21   22   23   24   25




Verilənlər bazası müəlliflik hüququ ilə müdafiə olunur ©genderi.org 2024
rəhbərliyinə müraciət

    Ana səhifə