Obertypparameter in Java
Wir erinnern an folgendes:
- Der Typ eines Parameters kann auch ein Referenztyp sein.
- Der Typ eines Argumentes muß ein Untertyp des Typs des zugehörigen Parameters sein.
- Wenn eine Methode mit einem Ausdruck als Kontext aufgerufen wird, dann muß die Signatur des Aufrufs im Typ des Ausdrucks vorkommen (der Compiler prüft das). Falls dies zutrifft, wird dann zur Laufzeit die entsprechende Nachricht an das Objekt, welches der Wert jenes Ausdrucks ist, geschickt.
Obertypparameter
Durch die Wahl eines geeigneten Parametertyps kann eine Methode Argumente verschiedener Typen, für die sie sinnvoll ist, akzeptieren.
Main.java
public final class Main
{public static void m( final java.lang.CharSequence sequence )
{ java.lang.System.out.printf( "%s%n%s%n%s%n%s%n",
sequence.length(),
sequence.charAt( 0 ),
sequence.subSequence( 0, 3 ),
sequence.toString() ); }public static void main( final java.lang.String[] args )
{ m( new java.lang.String( "Alpha" ));
m( new java.lang.StringBuilder( "Alpha" ));
m( new java.lang.StringBuffer( "Alpha" )); }}transcript
5
A
Alp
Alpha
5
A
Alp
Alpha
5
A
Alp
Alpha
Würde der Parametertyp unnötig einschränkend gewählt werden, wären sinnvolle Aufrufmöglichkeiten versperrt.
Main.java
public final class Main
{public static void m( final java.lang.String sequence )
{ java.lang.System.out.printf( "%s%n%s%n%s%n%s%n",
sequence.length(),
sequence.charAt( 0 ),
sequence.subSequence( 0, 3 ),
sequence.toString() ); }public static void main( final java.lang.String[] args )
{ m( new java.lang.String( "Alpha" ));
m( new java.lang.StringBuilder( "Alpha" ));
m( new java.lang.StringBuffer( "Alpha" )); }}transcript
Main.java:13: error: incompatible types: StringBuilder cannot be converted to String
m( new java.lang.StringBuilder( "Alpha" ));
^
Main.java:14: error: incompatible types: StringBuffer cannot be converted to String
m( new java.lang.StringBuffer( "Alpha" )); }}
^
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
2 errors
Ein weiteres Beispiel
Die unten verwendeten Nachrichten mit dem Verb »valueOf« ergeben ein Objekt ihrer Zielklasse, welches den Wert darstellt, der durch das Argument der Nachrichten angegeben wird.
Die Methoden namens »printInt« sollen die Antwort eines Objekts auf die Frage »intValue()?« ausgeben.
Main.java
public final class Main
{public static void printInt( final java.lang.Double p )
{ java.lang.System.out.println( p.intValue() ); }public static void printInt( final java.lang.Integer p )
{ java.lang.System.out.println( p.intValue() ); }public static void main( final java.lang.String[] args )
{ printInt( java.lang.Double.valueOf( "2" ));
printInt( java.lang.Integer.valueOf( "2" )); }}transcript
2
2
Es kann aber zu Problemen führen, wenn ein Programm so viel Redundanz enthält. Im Falle des obigen Programms sind die beiden Deklarationen der Methoden namens »printInt« fast gleich – sie unterscheiden sich nur im Typ des Parameters.
Das folgende Diagramm zeigt, daß der Typ »java.lang.Number« Obertyp von »java.lang.Double« und »java.lang.Integer« ist und eine Signatur »intValue()« enthält.
- Typhierarchie
.---------------------------.
| java.lang.Object |
|---------------------------|
|---------------------------|
'---------------------------'
^
/_\
|
|
.---------------------------.
| java.lang.Number |
|---------------------------|
|---------------------------|
| + intValue() |
'---------------------------'
^
/_\
|
|
.----------------'----------------.
| |
.---------------------------. .---------------------------.
| java.lang.Double | | java.lang.Integer |
|---------------------------| |---------------------------|
|---------------------------| |---------------------------|
| + intValue() | | + intValue() |
'---------------------------' '---------------------------'
Die statische Klassenmethode »java.lang.Integer.valueOf(java.lang.String)« liefert einen Wert vom Typ »java.lang.Integer«.
Die statische Klassenmethode »java.lang.Double.valueOf(java.lang.String)« liefert einen Wert vom Typ »java.lang.Double«.
Der Typ »java.lang.Number« ist ein gemeinsamer Obertyp von »java.lang.Integer« und »java.lang.Double« und enthält die Methode »intValue()«.
Daher kann im Aufruf einer Methode, die einen Parameter vom Typ »java.lang.Number« hat, sowohl ein Argumentausdruck vom Typ »java.lang.Integer« als auch vom Typ »java.lang.Double« verwendet werden.
Main.java
public final class Main
{public static void printInt( final java.lang.Number p )
{ java.lang.System.out.println( p.intValue() ); }public static void main( final java.lang.String[] args )
{ printInt( java.lang.Double.valueOf( "2" ));
printInt( java.lang.Integer.valueOf( "2" )); }}transcript
2
2
Der Typ »java.lang.Double« wäre zu speziell, so daß ein Argument beim Aufruf von »printInt« nicht akzeptiert werden würde.
Main.java
public final class Main
{public static void printInt( final java.lang.Double p )
{ java.lang.System.out.println( p.intValue() ); }public static void main( final java.lang.String[] args )
{ printInt( java.lang.Double.valueOf( "2" ));
printInt( java.lang.Integer.valueOf( "2" )); }}Protokoll
Main.java:9: error: method printInt in class Main cannot be applied to given types;
printInt( java.lang.Integer.valueOf( "2" )); }}
^
required: Double
found: Integer
reason: argument mismatch; Integer cannot be converted to Double
1 error
Der Typ »java.lang.Object« wäre zu allgemein, so daß die Methode »intValue()« nicht aufgerufen werden könnte.
Main.java
public final class Main
{public static void printInt( final java.lang.Object p )
{ java.lang.System.out.println( p.intValue() ); }public static void main( final java.lang.String[] args )
{ printInt( java.lang.Double.valueOf( "2" ));
printInt( java.lang.Integer.valueOf( "2" )); }}Protokoll
Main.java:5: error: cannot find symbol
{ java.lang.System.out.println( p.intValue() ); }
^
symbol: method intValue()
location: variable p of type Object
1 error- Wahl des Parametertyps („Goldlöckchen-Prinzip“)
java.lang.Object -- zu allgemein, Typ hat kein "intValue()", daher
^ erlaubt Uebersetzer ".intValue()"
/_\ nicht
|
|
java.lang.Number -- richtig, hat "intValue" und akzeptiert
^ java.lang.Integer-Argument und
/_\ java.lang.Double-Argument.
|
|
java.lang.Double -- zu speziell, Parameter akzeptiert
java.lang.Integer-Argument
nicht- Die Methode »printInt«
public static void printInt( final java.lang.Number p )
{ java.lang.System.out.println( p.intValue() ); }- Frage an einen Objektnamen
|
intValue()? | |
V |
|
.----------------------.
| p |
| - |
'----------------------'
Die Methode »printInt« sendet die Frage »intValue()?« an das Objekt »p«, ohne zu wissen, welche Klasse »p« genau hat. Dies ist ein Beispiel für Polymorphie, das zentrale Element der objektorientierten Programmierung.
Polymorphie
Polymorphie erlaubt die Formulierung abstrakter Algorithmen (wie »{ java.lang.System.out.println( p.intValue() ); }«), ohne daß dabei der genaue Typ der beteiligten Objekte (wie »p«) bekannt sein muß, und erlaubt es so, Objekte verschiedener Klassen flexibel miteinander kooperieren zu lassen. In einem späteren Teil des Kurses wird gezeigt werden, daß die Polymorphie es auch erlaubt, die Definition von Signaturen zu erweitern, ohne schon vorhandene Definitionen ändern zu müssen – dies erleichtert die Wartung großer Programme.
Noch ein Beispiel
Das folgende Diagramm zeigt, daß der Typ »java.lang.Object« Obertyp von »java.lang.String« und »java.io.PrintStream« ist und eine Signatur »toString()« enthält.
- Typhierarchie
.---------------------------.
| java.lang.Object |
|---------------------------|
|---------------------------|
| + toString() |
'---------------------------'
^
/_\
|
|
.----------------'----------------.
| |
.---------------------------. .---------------------------.
| java.lang.String | | java.io.PrintStream |
|---------------------------| |---------------------------|
|---------------------------| |---------------------------|
| + toString() | | + toString() |
'---------------------------' '---------------------------'
Jedes Objekt entscheidet an Hand seiner Klasse selber, was es auf eine Frage antwortet. Das folgende Programm zeigt, daß die Frage »toString()?« bei Versendung an Objekte verschiedener Klassen zu ganz unterschiedlichen Antworten führen kann.
Main.java
public final class Main
{public static void printString( final java.lang.Object o )
{ java.lang.System.out.println( o.toString() ); }public static void main( final java.lang.String[] args )
{ printString( "2" );
printString( java.lang.System.out ); }}transcript
2
java.io.PrintStream@6d06d69c- Frage an einen Objektnamen
|
toString()? | |
V |
|
.----------------------.
| o |
| - |
'----------------------'
Wir sehen in den obigen Programmen auch wieder Beispiele dafür, daß der Typ eines Ausdrucks nicht mit dem Typ seines Objekts übereinstimmen muß. Beispielsweise hat der Parameter »o« im letzten Programm den Typ »java.lang.Object«, während er für ein Objekt mit einem anderen Typ, wie »java.lang.String« oder »java.io.PrintStream« stehen kann.
»o« ist ein Ausdruck, aber kein Objekt! Das heißt: es ist im allgemeinen nicht bestimmt, für welches Objekt der Name »o« steht, da er im Verlaufe eines Programmes mal für das eine und mal für das andere Objekt stehen kann. Selbst die Klasse dieses Objektes ist nicht bestimmt!
Wir müssen also konstatieren, daß Nachrichten zuerst einmal an einen Ausdruck geschickt werden, und dann von dort aus zu einem Objekt weitergeleitet werden, dessen Klasse und Identität durch den Ausdruck aber nicht unbedingt bestimmt sein müssen. Das folgende Diagramm soll diese Weichenfunktion von Ausdrücken klarstellen.
- Darstellung zum Ausdruck »o.toString()«
|
|
toString()? | |
V |
|
|
.----------------------.
| o |
| :java.lang.Object |
| ~~~~~~~~~~~~~~~~~ |
'----------------------' Ausdruck
| (hat Referenztyp)
|
|
Zeitpunkt 0 | Zeitpunkt 1
.-------------------'-------------------.
| |
| |
| |
| |
.-----------------------. .-----------------------.
| "2" | | java.lang.System.out |
| : java.lang.String | | : java.io.PrintStream |
| ------------------ | | --------------------- |
'-----------------------' '-----------------------'
Objekt Objekt
(hat Klasse) (hat Klasse)
Die in dem obigen Diagramm dargestellte Laufzeitpolymorphie erlaubt es dieselbe Nachricht an verschiedene Objekt zu schicken, die sogar verschiedene Klassen (wie »java.lang.String« und »java.io.PrintStream«) haben können. Diese Laufzeitpolymorphie ist der entscheidenden Teil bei der objektorientierten Programmierung! Denn durch sie unterscheidet sich die objektorientierte Programmierung von der Programmierung mit abstrakten Datentypen, mit der sie sonst vieles gemein hat. Die Programmierung mit abstrakten Datentypen erlaubt es schon, Klassen zu bilden und Objekte von Klassen anzulegen, sie erlaubt aber keine Laufzeitpolymorphie.
Objektorientierte Programmierung ist Programmierung mit abstrakten Datentypen und Laufzeitpolymorphie.
Damit der Programmierer vom Verhalten der Objekt beim Empfang einer Nachricht nicht überrascht wird, sollte das Verhalten eines Objektes der Dokumentation seiner Klasse entsprechen und die Dokumentation einer Nachrichtensignatur in einer Klasse sollte eine Spezialfall der Dokumentation einer Methodensignatur in dem Referenztyp des Ausdrucks sein, dessen Wert das Objekt ist.
Das obenstehende Nachrichtenversanddiagramm entspricht dem folgenden Typdiagramm.
- Typhierarchie
.---------------------------.
| java.lang.Object |
|---------------------------|
|---------------------------|
| + toString() |
'---------------------------'
^
/_\
|
|
.----------------'----------------.
| |
.---------------------------. .---------------------------.
| java.lang.String | | java.io.PrintStream |
|---------------------------| |---------------------------|
|---------------------------| |---------------------------|
| + toString() | | + toString() |
'---------------------------' '---------------------------'
Lokale Variablen
Dasselbe Prinzip kann auch mit lokalen Variablen statt Parametern verwendet werden:
Main.java
public final class Main
{public static void main( final java.lang.String[] args )
{final java.lang.Object o = "2";
java.lang.System.out.println( o.toString() ); }}transcript
2
Die Verwendung von »java.lang.Object« an Stelle von »java.lang.String« in dem obigen Programm hat folgenden Vorteil: Wenn später einmal ein anderes Objekt als »"2"« verwendet werden soll, dann muß der Rest des Programms nicht verändert werden. Eine Änderung ist nur an einer Stelle nötig.
Main.java
public final class Main
{public static void main( final java.lang.String[] args )
{final java.lang.Object o = java.lang.System.out;
java.lang.System.out.println( o.toString() ); }}transcript
2
java.io.PrintStream@6d06d69c
Compiler-Prüfung
Der Übersetzer prüft bei der Übersetzung der folgenden Methode, daß der Verbaufruf »intValue()« im Typ des Kontexts »p«, also im Typ »java.lang.Number« vorhanden ist.
Methode
public static void printInt( final java.lang.Number p )
{ java.lang.System.out.println( p.intValue() ); }
In einigen Sprachen (nicht aber in Java ) kann solch eine Typ-Prüfung ausgeschaltet werden, indem der Typ des Parameters offengelassen wird. Der Übersetzer würde dann die Methode ohne Prüfung, ob der Verbaufruf »intValue()« im Typ des Kontexts »p« vorhanden ist, übersetzen.
hypothetische Methode
public static void printInt( final p )
{ java.lang.System.out.println( p.intValue() ); }
Falls ein Übersetzer soll tolerant sein sollte, wäre es dann aber möglich, die Methode »printInt« auch mit Argumenten aufzurufen, welche die Nachricht »intValue()?« gar nicht ermöglichen.
Main.txt
public final class Main
{public static void printInt( final p )
{ java.lang.System.out.println( p.intValue() );
java.lang.System.out.println( "println" ); }public static void main( final java.lang.String[] args )
{ printInt( "abc" ); }}
In diesem Falle würde die Java -Maschine dann erst bei der Ausführung des Programms einen Fehler melden.
- Konsole
Exception in thread "main" java.lang.NoSuchMethodError: String.intValue()
at Main.main(Main.java:4)
Die Mehrheit der großen Benutzer (Organisationen) der Programmiersprache Java wünscht es sich aber, daß Fehler durch den falschen Typ eines Arguments schon beim Übersetzen und nicht erst bei der Ausführung eines Programms angezeigt werden. Der Übersetzer prüft nämlich beim Übersetzen alle Teile eines Programms, während manche Teile des Programms nur selten unter bestimmten Bedingungen ausgeführt werden. Dies bedeutet, daß es schwierig sein kann, Fehler zu entdecken, die erst bei der Ausführung des Programms auftreten können. Solche Fehler sind gleichzeitig peinlicher, weil sie nicht beim Programmierer auftreten müssen, sondern erst beim Kunden auftreten könnten.
Das folgende Programm zeigt nun, daß Java Argumente mit falschen Typen (Typen, welche die in einer Methode verwendeten Methoden nicht enthalten) schon bei der Übersetzung erkennt.
Main.java
public final class Main
{public static void printInt( final java.lang.Number p )
{ java.lang.System.out.println( p.intValue() ); }public static void main( final java.lang.String[] args )
{ printInt( "abc" ); }}- Konsole
Main.java:6: error: method printInt in class Main cannot be applied to given types;
{ printInt( "abc" ); }}
^
required: Number
found: String
reason: argument mismatch; String cannot be converted to Number
1 error
Das folgende Programmbeispiele zeigt es, daß der Übersetzer es auch gleichzeitig erkennt, wenn eine Methode aufgerufen wird, die im Parameter nicht enthalten ist (genauergesagt: im Typ des Parameters nicht enthalten ist).
Main.java
public final class Main
{public static void printInt( final java.lang.Number p )
{ java.lang.System.out.println( p.value() ); }public static void main( final java.lang.String[] args )
{ printInt( java.lang.Double.valueOf( "2" )); }}- Konsole
Main.java:4: error: cannot find symbol
{ java.lang.System.out.println( p.value() ); }
^
symbol: method value()
location: variable p of type Number
1 error
Der Übersetzer stellt also einerseits sicher, daß das Argument einer Methode auch tatsächlich alle Methoden des Parametertyps enthält, und dann, daß die in der Methode aufgerufenen Methoden auch tatsächlich alle im Parametertyp enthalten sind. Somit stellt der Übersetzer insgesamt sicher, daß die in der Methode aufgerufenen Methoden auch alle im Typ des Arguments enthalten sind.
Diese Typprüfungen schon bei der Übersetzung bilden das Fundament der sogenannten statischen Typsicherheit von Java.
Man kann sich einen Parameter eines Typs wie einen Wächter vorstellen, der nur Argumente durchläßt, die auch tatsächlich den Parametertyp als Obertyp enthalten.
Statische und dynamische Typen
Die Typen von Ausdrücken werden auch oft als „statische Typen“ bezeichnet, weil sie durch den Quelltext bestimmt sind, und alles, was mit dem Quelltext zu tun hat, als „statisch“ bezeichnet wird, weil der Quelltext bei der Ausführung eines Programms unveränderlich („statisch“) ist.
Die Typen von Objekten werden auch oft als „dynamische Typen“ bezeichnet, weil Objekte erst bei der Ausführung eines Programms existieren, und alles, was mit der Ausführung zu tun hat, als „dynamisch“ bezeichnet wird, weil solche Dinge sich bei der Ausführung eines Programms („dynamisch“) verändern können.
Für die objektorientierte Programmierung mit Polymorphie ist nur ein dynamisches Typsystem nötig. Daher gibt es objektorientierte Programmiersprachen (wie Smalltalk ), die kein statisches Typsystem haben.
In Java gibt es zusätzlich ein statisches Typsystem, weil große Anwender die damit erreichte statische Typsicherheit wünschen. Das Erlernen der Programmiersprache wird aber dadurch erschwert, weil man gleich zwei Typsystem lernen muß: Das statische Typsystem und das dynamische.
Dokumentation von Nachrichtensignaturen
Am Anfang des Kurses hatten wir gelernt, wo wir die Dokumentation einer Signatur finden.
- Das Dokumentationsprinzip vom Anfang des Kurses
ℛ Dokumentationsprinzpip Die Dokumentation einer nicht-statischen Methode findet man unter dem Typ ihres Kontexts. Die Dokumentation einer statischen Methode findet man unter ihrem Kontext.
Tatsächlich wird das Verhalten einer Nachrichtenverarbeitung aber nicht vom Typ des empfangenden Ausdrucks bestimmt, sondern vom Typ des die Nachricht empfangenden Objekts. Dieses Verhalten muß allerdings mit der Dokumentation der Signatur im Typ des Ausdrucks verträglich sein – es muß also ein Spezialfall davon sein. Das neue Dokumentationsprinzip lautet nun:
ℛ Dokumentationsprinzpip Die Dokumentation einer nicht-statischen Nachrichtensignatur findet man unter dem Typ des die Nachricht empfangenden Objektes. Die Dokumentation einer statischen Signatur findet man unter ihrem Kontext.
Übungsfragen
? Übungsfrage
Die Methoden namens »printObject« sollen die Textdarstellung eines Objektes ausgeben.
Main.java
public final class Main
{public static void printObject( final java.io.PrintStream o )
{ java.lang.System.out.println( o.toString() ); }public static void printObject( final java.lang.String o )
{ java.lang.System.out.println( o.toString() ); }public static void main( final java.lang.String[] args )
{ printObject( java.lang.System.out );
printObject( "2" ); }}transcript
java.io.PrintStream@15db9742
2
Die Rümpfe der beiden Methoden namens »printObject« sind einander gleich. Wie können die beiden Deklarationen einer Methode namens »printObject« in dem obigen Programm durch nur eine einzige Methodendeklaration ersetzt werden?
? Übungsfragen
Main.java
public final class Main
{public static void printString( final java.lang.Object o )
{ java.lang.System.out.println( o.toString() ); }public static void main( final java.lang.String[] args )
{ printString( "2" ); }}
- Welchen Typ hat der Ausdruck »o« im Rumpf der Methode »printString« („statischer Typ“)?
- Welchen Typ hat das Objekt »o« während der Ausführung der Methode »printString« („dynamischer Typ“)?
? Übungsfragen
Main.java
public final class Main
{public static void printString( final java.lang.Object o )
{ java.lang.System.out.println( o.toString() ); }public static void main( final java.lang.String[] args )
{ printString( "2" );
printString( java.lang.System.out ); }}
- Welchen Typ hat der Ausdruck »o« im Rumpf der Methode »printString« („statischer Typ“)?
- Welche Typen hat das Objekt »o« während der Ausführung des Programms („dynamische Typen“)?
? Übungsfrage
Welcher Typ wird in dem folgenden Programm an Stelle der Ellipse benötigt, damit das Programm ohne Fehlermeldungen übersetzt werden kann?
Main.java
public final class Main
{public static void print( final … p )
{ java.lang.System.out.println( p.toString() ); }public static void main( final java.lang.String[] args )
{ print( new java.lang.String( "3" ));
print( new java.lang.StringBuffer( "3" ));
print( new java.lang.Integer( "3" )); }}transcript
3
3
3
? Übungsfrage
Welcher Typ wird in dem folgenden Programm an Stelle der Ellipse benötigt, damit das Programm die gezeigte Ausgabe erzeugt?
Main.java
public final class Main
{public static void printLength( final … p )
{ java.lang.System.out.println( p.length() ); }public static void main( final java.lang.String[] args )
{ printLength( new java.lang.String( "Hallo, Welt" ));
printLength( new java.lang.StringBuffer( "Hallo, Welt" ));
printLength( new java.lang.StringBuilder( "Hallo, Welt" )); }}java.lang.System.out
11
11
11
Refaktor (2) ⃗
Lagern Sie die Anweisungen aus der Methode »start«, welche vor der Anweisung »stage.setScene( new javafx.scene.Scene( vbox ));« stehen, in eine separate Methode »vbox()« aus, so daß die Anweisung »stage.setScene( new javafx.scene.Scene( vbox ));« dann als »stage.setScene( new javafx.scene.Scene( vbox() ));« geschrieben werden kann.
Bemerkung In der Regel sind zwei kleine Methoden besser als eine große Methode, vorausgesetzt, die Art der Zerlegung ist einigermaßen sinnvoll (so daß jede der neuen Methoden ein klar verständliche Aufgabe hat).
Main.java
public final class Main extends javafx.application.Application
{public void start( final javafx.stage.Stage stage )
{final javafx.scene.layout.VBox vbox
= new javafx.scene.layout.VBox();final javafx.scene.control.TextField text
= new javafx.scene.control.TextField( "text" );
vbox.getChildren().add( text );final javafx.scene.control.TextField text1
= new javafx.scene.control.TextField( "text" );
vbox.getChildren().add( text1 );stage.setScene( new javafx.scene.Scene( vbox ));
stage.show(); }}
Refaktor (3) ⃗
Setzen Sie die Zeilentripel, die zu jedem der beiden Textfelder gehören, jeweils in geschweiften Klammern und benennen Sie »text1« dann in »text« um.
Main.java
public final class Main extends javafx.application.Application
{public void start( final javafx.stage.Stage stage )
{final javafx.scene.layout.VBox vbox
= new javafx.scene.layout.VBox();final javafx.scene.control.TextField text
= new javafx.scene.control.TextField( "text" );
vbox.getChildren().add( text );final javafx.scene.control.TextField text1
= new javafx.scene.control.TextField( "text" );
vbox.getChildren().add( text1 );stage.setScene( new javafx.scene.Scene( vbox ));
stage.show(); }}
Refaktor (4) ⃗
In dem folgenden Programm finden sich in der Methode »start« zwei Tripel von Zeilen, die einander fast gleich sind. Erstellen Sie eine Methode und rufen Sie diese Methode zwei Mal in geeigneter Weise auf, um schließlich wieder dasselbe Verhalten beobachten zu können, wie bei dem Originalprogramm, aber weniger Wiederholung im Quelltext zu haben.
Main.java
public final class Main extends javafx.application.Application
{public void start( final javafx.stage.Stage stage )
{final javafx.scene.layout.VBox vbox
= new javafx.scene.layout.VBox();final javafx.scene.control.TextField text
= new javafx.scene.control.TextField( "text" );
vbox.getChildren().add( text );final javafx.scene.control.TextField text1
= new javafx.scene.control.TextField( "text" );
vbox.getChildren().add( text1 );stage.setScene( new javafx.scene.Scene( vbox ));
stage.show(); }}
Hinweis für den Dozenten ► N: introduce method
Übungsaufgabe
Hinweis für den Dozenten ► Diese Übungsaufgabe sollte nicht vor der Nachbesprechung der vorherigen Übungsaufgabe bearbeitet werden.
Schreiben Sie an die Stelle »/* B */« eine Anweisung ein, welche eine Methode mit dem Methodennamen »m« mit dem Textfeld »text« als Argument aufruft.
Fügen sie alsdann an der Stelle »/* A */« eine Deklaration einer statische Klassenmethode mit dem Methodennamen »m« zu der Klasse hinzu, welche ein Textfeld vom Typ »javafx.scene.control.TextField« als Argument akzeptiert. Im Rumpf der Methodendeklaration soll dann die Zeichenfolge jenes Textfeldes ausgegeben werden, und danach soll die Zeichenfolge jenes Textfeldes als die Zeichenfolge »def« festgelegt werden.
public final class Main extends javafx.application.Application
{/* A */
public void start( final javafx.stage.Stage stage )
{
final javafx.scene.control.TextField text
= new javafx.scene.control.TextField( "" );
/* B */javafx.application.Platform.exit();
System.exit( 0 ); }}