Diese Lektion wird gerade (im Winter 2005-2006) überarbeitet. Sie enthält daher noch ungeordnete und nicht ausformulierte Notizen.
Signaturen von Operationsaufrufen
Zunächst sollen Operationsaufrufe betrachtet werden, die aus einem Selektor und einem Argument bestehen.
Operationsaufrufe
f( 23 )
g( 2. )
Der Selektor (in den Beispielen "f" bzw. "g") ist eine Bezeichner, das Argument (in den Beispielen "23" bzw. "2.") ist ein Ausdruck.
Die Signatur eines solchen Aufrufs ist durch dessen Selektor und die Typen seiner Argumente gegeben.
Signaturen von Operationsaufrufen
f( int )
g( double )- ? Signaturen
- Welche der folgenden Aufrufe haben die gleiche Signatur?
Operationsaufrufe
f( 23 )
f( 12 )
g( 2. )
f( 2. )
Parameterbeschreibungen
Eine Parameterbeschreibung besteht aus einer Angabe eines Typs, dem ein Bezeichner, der Parametername, folgen kann.
Parameterbeschreibungen
int
double a
Eine Parameterbeschreibung beschreibt einen Parameter. Daher ist der angegebene Typ der Typ des Parameters (der Parametertyp ).
So ist der Text "int" eine Parameterbeschreibung ohne Parameternamen und der Text "double a" ist eine Parameterbeschreibung mit einem Parameternamen.
Der Parametername ist formal weniger relevant und dient eher als Merkhilfe zur Bedeutung des Parameters. Entscheidend ist oft nur der Typ des Parameters.
Signatur einer Operationsbeschreibung
Eine Wertoperation ist ein Dienst, der auf einen passenden Aufruf hin, einen Wert liefert.
Eine Wertoperation ist formal durch ihren Selektor und ihren Parametertyp gekennzeichnet, die beide zusammen die Signatur der Operation bilden.
Signaturen von Operationen
f( int )
g( double )
g( double a )
Ein eventueller Parametername dient nur als Hilfe zum merken der Bedeutung des Parameters, hat aber sonst für die Signatur keine Relevanz. Daher ist die Signatur "g( double )", die Signatur "g( double a )" und die Signatur "g( double x )" formal gleich.
- ? Signaturen
- Welche der folgenden Signaturen gelten als formal gleich?
Signaturen
f( int )
f( double )
g( int x )
In Java wird der Selektor auch Name der Methode (zu der die Signatur gehört) genannt. In der Sprachbeschreibung heißt es: “Two methods have the same signature if they have the same name and argument types. ” (JLS 3, 8.4.2 Method Signature )
Der Aufruf einer Operation eines Dienst
Damit eine Operation ausgeführt wird, muß es irgendeinen Dienst (Ausführer, Implementator) geben, der sie ausführt.
In der objektorientierten Programmierung wird beim Aufruf einer Operation der Dienst, der die Operation ausführen soll, ausdrücklich angegeben.
In Java wird dazu der Dienst mit einem Punkt getrennt vor die Operation geschrieben.
Aufruf einer Operation eines Dienstes
d.f( 2 )
e.f( 2 )- Allegorie
- Das Produkt „Pizza Marinara“ kann bei verschiedenen Diensten (Restaurants) bestellt werden. Je nach dem herstellenden Dienst erhält man bei der gleichen Bestellung „Pizza Marinara“ auch etwas unterschiedliche Produkte. Aber offensichtlich muß man die Bestellung bei irgendeinem passenden Restaurant einreichen, wenn man eine Pizza Marinara zu erhalten wünscht.
Bestellung einer Pizza bei verschiedenen Restaurants
Paradiso.Pizza( Marinara )
Broadway.Pizza( Marinara )
Akzeptieren von Aufrufen
Ein Dienst kann nicht alle beliebigen Operation wirklich ausführen, die man von ihm verlangen könnte, sondern nur einige bestimmte Operationen, für die er vorbereitet wurde.
So wird ein Dienst passende Aufrufe akzeptieren und unpassende Aufrufe zurückweisen.
Was passiert, wenn eine Nachricht zurückgewiesen wird ist im allgemeinen nicht definiert. Man kann es als einen Fehler ansehen Nachrichten an einen Empfänger zu schicken, die dieser zurückweist.
Der Dienst "Math" akzeptiert beispielsweise den Aufruf "abs( 2 )".
Ein akzeptabler Aufruf
Math.sin( 0 )
Der Aufruf "Math.sin( 2 )" ruft die Operation "abs( 2 )" des Dienstes "Math" auf. Man kann dies wie eine Bestellung eines Wertes ansehen, die an den Dienst geschickt wird, weswegen der entsprechende Vorgang in UML auch wie die Versendung einer Nachricht dargestellt wird.
Versendung der Nachricht "abs( 0 )" an den Dienst "Math"
|
| |
| | abs( 0 )
| V
|
.---------------------------------------.
| Math |
'---------------------------------------'
Zurückweisen von Aufrufen
Der Dienst "Math" weist den Aufruf "abt( 2 )" hingegen zurück.
Ein inakzeptabler Aufruf
Math.sin( 0 )
Das folgende Beispiel zeigt die Versendung einer vom Typ des Empfängers nicht unterstützten Nachricht.
Versendung einer nicht-unterstützten Nachricht
public class Dot
{ public static void main(String[] args)
{ Math.dot(); }}Bericht des Übersetzers
Test.java:3: cannot find symbol
symbol : method dot()
location: class java.lang.Math
{ Math.dot(); }}
^
1 error
Das Zurückweisen der Nachricht erfolgt hier also bereits zur Übersetzungszeit durch den Übersetzer und nicht erst dann, wenn die Nachricht zur Laufzeit tatsächlich versendet wird.
Der Programmtext wird als statisch bezeichnet, weil er während des Programmablaufs nicht verändert wird, also statisch (d.h. unverändert) ist. Die Information über den Typ eines Ausdrucks, die bereits aufgrund des Quelltextes bekannt ist, wird auch als statische Typinformation bezeichnet.
Wenn der Übersetzer, wie hier, während der Übersetzung eine Versendung an Hand der im zugänglichen statischen Typinformation prüft, so spricht man auch von statischer Typprüfung.
Diese Lektion wird gerade (im Winter 2005-2006) überarbeitet. Sie enthält daher noch ungeordnete und nicht ausformulierte Notizen.
[revmark]
Diensttypen
Toleranz/Verträglichkeit beim Akzeptieren (implizite Typerweiterung)
Formale Operationen
formale Operationen
void print( int i )
double sin( double a )
Die Signatur zusammen mit dem Typ des Ergebnisses ist ein formaler Typ einer formalen Operation (formaler Operationstyp). So kann man sagen, die formale Operation "print" habe den formalen Typ "void( int )", d.h., sie akzeptiere ein int-Argument und liefere kein Ergebnis und die formale Operation "sin" habe den formalen Typ "double( double )", d.h., sie akzeptiere ein double-Argument und liefere ein double-Ergebnis. Das Attribut „formal“ soll hierbei zum Ausdruck bringen, daß dieser formale Typ nur die formalen Eigenschaften der formalen Operation beschreibt, er aber nicht angibt, was diese Operation eigentlich bedeutet oder was ihr Sinn ist.
Zu einer vollständigen Operation fehlt der formalen Operation noch die Beschreibung des Verhaltens der Operation.
Der hier definierte Typbegriff ist zu unterscheiden von dem Begriff des „primitiven Typs“, in dem eine Typ eine Menge von Werten ist. Daher wird auch eine andere Bezeichnung dafür verwendet.
Ein formaler Typ ist eine Menge von formalen Operationstypen.
Man sagt, daß der Typ diese Operationstypen unterstützt, akzeptiert, bietet oder enthält .
Ein Empfänger kann einen bestimmten formalen Typ haben. Die Operationstypen des formalen Typs bestimmen dann, welche Nachrichten der Empfänger akzeptiert.
Der formale Typ "Mathtype"
double sin( double a )
double tan( double a )
double cos( double a )
Operationen mit mehreren Parameter
... oder ohne Parameter
Ausdrucklisten
Eine durch Kommas getrennte Liste von Ausdrücken ist eine Ausdruckliste.
Ausdruckliste
2.
2., 4.
2, 3.
Parameterlisten
Eine durch Kommas getrennte Liste von Parameterbeschreibungen ist eine Parameterliste.
Parameterlisten
int
int, double
int a
int a, double b
Eine durch Kommas getrennte Liste von Ausdrücken ist eine Ausdruckliste.
Ausdruckliste
2.
2., 4.
2, 3.
Parameterlisten
Eine durch Kommas getrennte Liste von Parameterbeschreibungen ist eine Parameterliste.
Parameterlisten
int
int, double
int a
int a, double b
Verträglichkeit von Ausdrücken mit Parameterbeschreibungen
Ein Ausdruck ist mit einer Parameterbeschreibung verträglich, wenn der Ausdruck mit dem Typ der Parameterbeschreibung zuweisungsverträglich ist.
Parameterbeschreibungen und zuweisungsvertraegliche Ausdruecke
Parameterbeschreibung zuweisungsvertraeglicher Ausdruck
double 2.
double a 2.
double b 2.
double c 2
double d 2. + 1.
int 2
int i 2
Verträglichkeit von Ausdrucklisten mit Parameterlisten
Wenn eine Ausdruckliste so viele Ausdrücke enthält wie eine bestimmte Parameterliste an Parameterbeschreibungen enthält und jeder Ausdruck der Ausdruckliste jeweils mit dem entsprechenden Typ des Parameter der Parameterliste zuweisungsverträglich ist (der erste Ausdruck mit dem ersten Parametertyp, der zweite Ausdruck mit dem zweiten Parametertyp u.s.w.), dann ist die Ausdruckliste mit der Parameterliste verträglich.
Vertraegliche Listen von Parametern und Ausdruecken
Parameterliste vertraegliche Ausdruckliste
double 2.
double, int 2., 3
double x, int i 2., 3
double, double 2., 3
double u, double v 2., 3
double, double 2., 3.- Verträglichkeit
- Welche der folgenden Paare von Parameterlisten und Ausdrucklisten sind verträglich?
Listen von Parametern und Ausdruecken
Parameterliste vertraegliche Ausdruckliste double 2
int i 2
int 2, 2
double 2, 2
int a, int b 3, 4, 2.9
int i, int j 4, 3.2
Semantik
Diese Lektion wird gerade (im Winter 2005-2006) überarbeitet. Sie enthält daher noch ungeordnete und nicht ausformulierte Notizen.
Wenn ein Empfänger die Nachricht akzeptiert, dann verwirklicht er ein bestimmtes Verhalten in Abhängigkeit von der Nachricht. Der Empfänger legt als das Verhalten des Versendung fest.
Eine Nachricht zu versenden, bedeutet, sie so zu verwenden, daß ihr Verhalten dabei eintritt.
Eine Anwendung einer Operation verlangt das durch die Spezifikation der Operation festgelegte Verhalten.
Beschreibungen des Typs und der Bedeutung (Semantik, Verhalten)
Nachrichten in Java
Verhalten
Das Verhalten eines Ausdrucks umfaßt:
- die Aktionen (Wirkungen) und
- einen Wert.
Beispielsweise kann der Ausdruck "print( 2 )" die Aktion der Ausgabe einer Darstellung des Wertes "2" haben, der Ausdruck "Math.sin( 0 )" kann den Wert "0" haben.
Spezifikation von Operationen
Zu einer formalen Operation kann eine Spezifikation geschrieben werden. Sie beschreibt das Verhalten einer formalen Operation in Abhängigkeit von den Umständen einer Aktivierung dieser formalen Operation. Zu den Umständen einer solchen Aktivierung gehören Zustände von Systemen zum Zeitpunkt der Aktivierung und die Werte der Argumente der Aktivierung.
Eine Spezifikation gibt einer Anwendung einer formalen Operation also eine bestimmte Bedeutung. Eine formale Operation ist nur eine Festlegung des Typs der Argumente und des Ergebnisses, die Spezifikation fügt dann eine Bedeutung hinzu, die in diesem Zusammenhang auch manchmal (nicht ganz korrekt) als „Semantik“ bezeichnet wird.
Dabei kann eine Spezifikation auch Teil einer Menge von Spezifikationen sein, so daß bestimmte in einer Spezifikation verwendeten Begriffe erst im Kontext anderer Spezifikationen dieser Menge vollständig verständlich sind.
Eine Spezifikation kann das Verhalten einer formalen Operation auch für bestimmte Umstände unbestimmt lassen.
Eine Operation, die eine Wert oder eine Wirkung hat ist eine Wertoperation bzw. eine Wirkoperation.
Spezifikationen
void print( int i )
Prints an integer.
double sin( double a )
Returns the trigonometric sine of an angle.
Die erste Spezifikation legt für die Operation "print" fest, daß eine Anwendung dieser Operation keinen Wert hat ("void"), aber ein Wirkung (“Prints an integer ”) hat.
Die zweite Spezifikation legt für die Operation "sin" fest, daß eine Anwendung dieser Operation einen Wert vom Typ "double" hat, nämlich den Sinus des durch das Argument bestimmten Winkels (“Returns the trigonometric sine of an angle. ”). Da die Spezifikation keine Wirkung beschreibt, kann man annehmen, daß diese Operation wirkungslos ist.
Eine formale Operation zusammen mit einer Spezifikation bestimmt eine Operation.
In etwa kann man daher auch sagen: Eine Operation ist ein formale Operation zusammen mit einer Erklärung der Bedeutung dieser formalen Operation.
Wirkungen und Werte
Nachrichten, Operationen und Versendungen können wie Methoden oder Routinen Wirkungen oder Werte haben. Entsprechend lassen sich alle dafür gebildeten Begriffe übertragen. So ist eine Wirknachricht beispielsweise eine Nachricht, deren Versendung eine Wirkung hat. Eine Wertnachricht ist eine Nachricht, deren Versendung einen Wert hat. Entsprechend kann man auch von einer Wirkversendung oder einer Wertoperation sprechen.
Diese Lektion wird gerade (im Winter 2005-2006) überarbeitet. Sie enthält daher noch ungeordnete und nicht ausformulierte Notizen.
722075 jf — Empfänger von Nachrichten
Empfänger
Formaler Typ
Semantischer Typ
Ein semantischer Typ ist eine Menge von Operationen.
Das bedeutet, daß eine semantischer Typ eine Menge von Operationstypen festlegt und für diese Operationstypen ein bestimmtes Verhalten spezifiziert.
Zu einer Nachricht kann es in einem Typ mehrere Signaturen geben, mit denen die Nachricht verträglich ist. (Hierfür sind nur die Signaturen und nicht die ganzen Operationstypen mit dem Rückgabewert relevant.) Dann wird nach bestimmten Regeln ermittelt, welche Signatur mit der Nachricht am besten verträglich ist. Die Nachricht wird dann dieser Signatur zugeordnet. Falls solch eine Zuordnung nicht eindeutig möglich ist, wird die Nachricht zurückgewiesen. Genau die Nachrichten, denen eindeutig eine Signatur zugeordnet werden kann, werden dann akzeptiert.
Der semantische Typ "Mathtype"
double sin( double a )
Returns the trigonometric sine of an angle.
double tan( double a )
Returns the trigonometric tangent of an angle.
double cos( double a )
Returns the trigonometric cosine of an angle.
Die Nachricht "sin( 0 )" kann beispielsweise der Signatur "sin( double a )" bzw. der entsprechenden Operation zugeordnet werden.
Eng verwandt mit dem hier definierten Begriff „semantischer Typ“ ist der übliche Begriff des abstrakten Datentyps, der ebenfalls einen Typ beschreibt, der nur durch seine Operationen definiert ist.
Diese Typen (formale Typen, semantische Typen und abstrakte Datentypen) sind zu unterscheiden von den primitiven Typen, die eher Mengen von Werten ähneln. Wenn nur von einem „Typ“ oder einem „Datentyp“ gesprochen wird, muß dem Zusammenhang entnommen werden, was gemeint ist.
Typ eines Empfängers
Ein Empfänger kann einen bestimmten semantischen Typ haben, dann legt dieser semantische Typ das Verhalten von Nachrichten fest, die an den Empfänger geschickt werden.
Ein Empfänger unterstützt, akzeptiert, bietet oder enthält eine Operation wenn sein semantischer Typ diese Operation unterstützt.
Durch den semantischen Typ eines Empfängers wird festgelegt, welche Operationen der Empfänger unterstützt und was diese Operationen machen.
Diese Lektion wird gerade (im Winter 2005-2006) überarbeitet. Sie enthält daher noch ungeordnete und nicht ausformulierte Notizen.
Eine Nachricht ist mit einer Signatur verträglich, wenn der Selektor der Nachricht, dem Selektor der Signatur gleicht und die Argumentliste der Nachricht mit der Parameterliste der Signatur verträglich ist.
vertraegliche Nachrichten
Signatur vertraegliche Nachricht
f() f()
g( int ) g( 2 )
h( int, double ) h( 2, 3. )
h( int, double ) h( 2, 3 )
k( int a ) k( 2 )
s( int a, double b ) s( 2, 3. )
Eine Nachricht wird auch als Anwendung der Signatur (auf eine Ausdruckliste oder eine Argumentliste) bezeichnet. Man spricht auch von einer Anwendung des Signatur auf die Argumente, also sagt beispielsweise die Nachricht "g( 2 )" sei eine Anwendung der Signatur "g( int )" auf das Argument "2". (Manchmal spricht man auch nur von einer Anwendung des Selektors "g".)
Implizite Typerweiterung
Es ist möglich, eine Methode mit einem Argument eines verträglichen aber weniger umfassenden Typs als den des Parameters der Methode aufzurufen. So darf eine Methode, mit einer Gleitkommazahl vom Typ "double" als Parameter, auch mit einem Ausdruck vom Typ "int" als Argument aufgerufen werden, weil solch ein Ganzzahl-Argument vom Typ "int" zu einer Gleitkommazahl vom Typ "double" erweitert werden kann.
Die Methode "Math.cos" hat ein Parameter vom Typ "double" spezifiziert. (Dieser Parameter wird in der folgenden Synopse durch den Namen "a" bezeichnet, der aber für den Klienten keine Bedeutung hat.)
cos [Synopse]
java.lang
Class Math
static double cos( double a )
Das folgende Beispiel zeigt den Aufruf der Methode "Math.cos" mit dem Argument "0" vom Typ "int".
Extend.java
public class Extend
{ public static void main( String[] args )
{ System.out.println( Math.cos( 0 )); }}System.out
1.0
Keine Implizite Typeinschränkung
Eine automatische Typwandlung ist aber in Java nicht immer möglich. Wenn einer Methode, deren Parameter vom Typ "int" ist, als Argument eine Gleitkommazahl vom Typ "double" übergeben wird, so würden bei der Umwandlung Informationen über die Nachkommastellen verloren gehen. Nach Auffassung der Schöpfer der Programmiersprache Java darf solch ein Informationsverlust nicht ohne ausdrückliche Billigung des Programmierers erfolgen. Der Ausdruck wird daher nicht automatisch umgewandelt und der Compiler erzeugt eine Fehlermeldung. Es ist zum Verständnis des folgenden Beispiels nicht so wichtig, zu wissen, was die Methode "Float.intBitsToFloat" genau bedeutet, sie hat aber jedenfalls einen Parameter vom Datentyp "int" und kann das Argument "0." vom Datentyp "double" nicht akzeptieren.
Intend.java
public class Intend
{ public static void main( String[] args )
{ System.out.println( Float.intBitsToFloat( 0. )); }}Konsole
javac Intend.java
Intend.java:3: intBitsToFloat(int) in java.lang.Float cannot be applied to (double)
{ System.out.println( Float.intBitsToFloat( 0. )); }}
^
1 error
Der Datentyp eines Arguments würde also dann implizit umgewandelt werden, wenn die Uminterpretation in den Parametertyp so erfolgen kann, daß dabei keine Informationen verloren gehen.
Zuweisungsverträglichkeit
Wenn der Typ eines Ausdrucks so stillschweigend in einen Typ gewandelt werden kann, wie dies bei der Zuweisung des Ausdrucks an eine Variable dieses Typs geschieht, dann ist der Ausdruck mit dem Typ zuweisungsverträglich.
Um zu ermitteln, ob ein Ausdruck mit einem Typ zuweisungsverträglich ist, muß man also testen, ob es möglich wäre, diesen Ausdruck auf der rechten Seite einer Zuweisung an eine Variable dieses Typs zu verwenden.
Zuweisungsvertraegliche Ausdruecke
Typ zuweisungsvertraeglicher Ausdruck moegliche Zuweisung
double 2. double x = 2.;
double 2 double x = 2;
double 2. + 1. double x = 2. + 1.;
int 2 int i = 2;
Übungsfrage Nennen Sie eine Kombination eines Typs und eines Ausdrucks, die nicht zuweisungsverträglich sind!
Ein Ausdruck der Ausdruckliste einer Nachricht wird auch Argument der Nachricht genannt. Die Ausdruckliste einer Nachricht heißt auch Argumentliste.
Eine Signatur ist ein Bezeichner, dem eine eingeklammerte Parameterliste folgt.
Signaturen
f()
g( int )
h( int, double )
k( int a )
s( int a, double b )
Der Bezeichner wird auch der Selektor der Signatur genannt.