Statische Methodendeklarationen und Objekte in Java
Wir haben bereits im Grundkurs Methodendeklarationen geschrieben, die Objekte der Klasse »java.lang.String« als Argumentwert entgegennehmen oder Objekte der Klasse »java.lang.String« als Rückgabewert zurückgeben, obwohl wir damals dabei noch nicht von „Objekten“ gesprochen haben.
In Java dürfen auch alle anderen Referenztypen (neben »java.lang.String«) als Parametertypen oder Rückgabetypen in einer Methodendeklaration verwendet werden.
Die folgende Methodendeklaration ist ein Beispiel einer Deklaration einer Methode, die ein Objekt zurückgibt. Wie schon im Grundkurs behandelt muß der Typ des Rückgabeausdrucks ein Untertyp des Rückgabetyps der Methode sein.
- (Methodendeklaration)
public static java.lang.Object method(){ return ""; }
Die folgende Methodendeklaration ist ein Beispiel einer Deklaration einer Methode, die ein Objekt als Argumentwert akzeptiert. Wie schon im Grundkurs behandelt muß der Typ des Arguments ein Untertyp des Typs des Parameters sein.
- (Methodendeklaration)
public static void method( final java.lang.Object object )
{ java.lang.System.out.println( object ); }
Objektparameter
Ein Programm wie das folgenden hatten wir bereits früher behandelt. Da »i« eine von »n« unabhängige Variable ist, die lediglich eine Kopie des Wertes aus »n« erhält, wirkt sich die Veränderung des Wertes von »i« nicht auf »n« aus.
Main.java
public final class Main
{public static void inc( int i )
{ i = i + 1; }public static void main( final java.lang.String[] args )
{ int n = 2;
inc( n );
java.lang.System.out.println( n ); }}transcript
2
Ein etwaiger Flüchtigkeitsfehler des sinnlosen Versuches, eine Argumentvariable durch Veränderung der Parametervariablen zu verändern, hätte durch Deklaration der Parametervariablen mit »final« vermieden werden können.
Bei Objektvariablen geschieht eigentlich dasselbe: Der Parameter »p« im folgenden Programm erhält das Objekt »a« und Zuweisungen, die mit »p =« beginnen, wirken sich ebenfalls nicht auf »a« aus.
Während die Zahl 2 jedoch nicht verändert werden kann, können Objekte verändert werden. Da »p« zunächst das gleichen Objekt enthält wie »a« sind Änderungen an dem in »p« enthaltenem Objekt gleichzeitig auch Änderungen an dem in »a« enthaltenen Objekt.
Main.java
public final class Main
{public static void scale( java.awt.geom.Point2D.Double p )
{ p.x = 2 * p.x; p.y = 2 * p.y;
p = new java.awt.geom.Point2D.Double(); }public static void main( final java.lang.String[] args )
{ final java.awt.geom.Point2D.Double a = new java.awt.geom.Point2D.Double();
a.x = 1.0; a.y = 4.0;
java.lang.System.out.printf( "%s, %s%n", a.x, a.y );
scale( a );
java.lang.System.out.printf( "%s, %s%n", a.x, a.y ); }}transcript
1.0, 4.0
2.0, 8.0
Laufzeit-Polymorphie
In dem folgenden Programm wird die Implementation von »toString« erst spät (zur Laufzeit, bei der Auswertung des Ausdrucks »o.toString()«) durch die Klasse des Objektes festgelegt. Man schickt jedem der drei Objekt die Aufruf-Nachricht »toString()«, und jedes der drei Objekte verwendet dann ein anderes Verfahren, um die Aufruf-Nachricht auszuführen. (Das Verfahren wird durch die Klasse des Objektes festgelegt.) Auch hier erkennt man also wieder die Laufzeit-Polymorphie.
Main.java
public class Main
{public static void print( final java.lang.Object o )
{ java.lang.System.out.println( o.toString() ); }public static void main( final java.lang.String[] args )
{ print( "Alpha" );
print( new java.awt.geom.Point2D.Double() );
print( java.lang.System.out ); }}transcript
Alpha
Point2D.Double[0.0, 0.0]
java.io.PrintStream@15db9742
Übungsfragen
? Ausgabe vorhersagen
Welche Ausgabe erzeugt das folgende Programm?
Main.java
public final class Main
{public static void inc( final java.awt.geom.Point2D.Double p )
{ p.x = p.x + 1;
p.y = p.y + 1; }public static void main( final java.lang.String[] args )
{ final java.awt.geom.Point2D.Double a = new java.awt.geom.Point2D.Double();
a.x = 1.0;
a.y = 4.0;
inc( a );
java.lang.System.out.println( a.x );
java.lang.System.out.println( a.y ); }}
Übungsaufgaben
Man schickt eine Nachricht an ein Objekt, indem man hinter einen Ausdruck für das Objekt, einen Punkt und einen Verbaufruf schreibt. Der Verbaufruf gibt dabei die Nachricht an, die aus dem Verb des Verbaufrufes und den Werten seiner Argumente besteht. Um die Nachricht »println( 2 )« an das Objekt »java.lang.System.out« zu schicken, kann man beispielsweise schreiben: »java.lang.System.out.println( 1 + 1 )«.
Das folgende Beispiel zeigt, wie mit dem Verb »getLogger« ein Logger-Objekt erzeugt wird, dessen Name »abc« lautet. Anschließend wird der Name des Objekts ausgegeben, der durch Schicken der Nachricht »getName()« an das Objekt erhalten wurde.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ final java.util.logging.Logger l
= java.util.logging.Logger.getLogger( "abc" );java.lang.System.out.println( l.getName() ); }}
transcript
abc
Übungsaufgaben Übergabe und Rückgabe von Objekten
/ Übergabe zweier Zahlen
Schreiben Sie eine Deklaration einer statischen Klassenmethode namens »printSum«, welche ein java.awt.geom.Point2D.Double-Objekt als Argument entgegennimmt. Diese Methode soll die Summe der beiden Zahlen in ihrem Parameterobjekt und ein Zeilenende ausgeben.
Rufen Sie diese Methode »printSum« dann im Hauptprogramm (also in der Methode »main(java.lang.String[])«) mit einem java.awt.geom.Point2D.Double-Objekt, welches die beiden Zahlen »6.0« und »23.0« enthält, als Argument auf. (Es sollte »29.0« und ein Zeilenende ausgegeben werden.)
/ Rückgabe zweier Zahlen
Schreiben Sie eine Deklaration einer parameterlosen statischen Klassenmethode namens »pair«, welche ein java.awt.geom.Point2D.Double-Objekt, welches die beiden Zahlen »14.0« und »7.0« enthält, als Ergebnis zurückgibt.
Rufen Sie diese Methode »pair« dann im Hauptprogramm (also in der Methode »main(java.lang.String[])«) auf. Als Ergebnis erhalten Sie dann ein java.awt.geom.Point2D.Double-Objekt. Geben Sie dann im Hauptprogramm die Summe der beiden Felder jenes erhaltenen Objektes aus!
Übungsaufgaben Deklaration statischer Erzeugungsmethoden
Unter einer Anfertigungsmethode verstehen wir eine Methode, die ein Objekt ergibt. Eine Erzeugungsmethode ist eine Anfertigungsmethode, die bei jedem Aufruf eine neues Objekt ergibt (während eine Anfertigungsmethode auch zweimal dasselbe Objekt ergeben könnte).
/ Beispielaufgabe
Schreiben Sie eine Erzeugungsmethode für java.lang.String-Objekte.
- Beispiellösung ohne Parameter (Methodendeklaration)
public static java.lang.String makeString()
{ return new java.lang.String(); }
/ Übungsaufgabe
Schreiben Sie eine Anfertigungsmethode für java.lang.String-Objekte, die einen String mit einer übergebenen int-Zahl erzeugt.
- Beispielloesung mit Parameter (Methodendeklaration)
public static java.lang.String makeString
( final int i )
{ return new java.lang.String( "" + i ); }
/ Übungsaufgabe (1)
Programmieren Sie eine parameterlose Erzeugungsmethode »makeObject« für Objekte der Klasse »java.lang.Object«.
Falls die von Ihnen geschrieben Methodendeklaration an Stelle der Ellipse »…« in den folgenden Testrahmen eingesetzt wird, sollte das sich dann ergebende Programm »richtig« ausgeben.
Main.java
public final class Main
{…
public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( ( makeObject().getClass().equals( new java.lang.Object().getClass() )&&
makeObject() != makeObject()?
"" : "nicht ganz " )+ "richtig" ); }}
/ Übungsaufgabe
Ein Objekt der Klasse »java.lang.Integer« ist ein Objekt, das einen int-Wert enthält, der bei der Erzeugung angegeben und mit der nicht-statischen Methode »intValue()« abgefragt werden kann.
Programmieren Sie eine Anfertigungsmethode »makeInteger« für Objekte der Klasse »java.lang.Integer«, die einen int-Wert als Argument akzeptiert und dazu ein java.lang.Integer-Objekt ergibt, das die Nachricht »intValue()« mit dem der Anfertigungsmethode übergebenen int-Wert beantwortet.
Beispielsweise sollte »makeInteger( 81 ).intValue()« den Typ »int« und den Wert »81« haben.
Falls die von Ihnen geschrieben Methodendeklaration an Stelle der Ellipse »…« in den folgenden Testrahmen eingesetzt wird, sollte das sich dann ergebende Programm »richtig« ausgeben.
Main.java
public final class Main
{…
public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( ( makeInteger( 2 ).getClass().equals
( new java.lang.Integer( 2 ).getClass() )&&
makeInteger( 2 ).intValue() == 2 &&
makeInteger( -2 ).intValue() == -2?
"" : "nicht ganz " )+ "richtig" ); }}
/ Übungsaufgabe
Programmieren Sie eine Anfertigungsmethode »makeDouble« für Objekte der Klasse »java.lang.Double«, die einen double-Wert als Argument akzeptiert und dazu ein java.lang.Double-Objekt ergibt, das die Nachricht »doubleValue()« mit dem der Anfertigungsmethode übergebenen double-Wert beantwortet.
Beispielsweise sollte »makeDouble( 8.1 ).doubleValue()« den Typ »double« und den Wert »8.1« haben.
Falls die von Ihnen geschrieben Methodendeklaration an Stelle der Ellipse »…« in den folgenden Testrahmen eingesetzt wird, sollte das sich dann ergebende Programm »richtig« ausgeben.
Main.java
public final class Main
{…
public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( ( makeDouble( 2 ).getClass().equals
( new java.lang.Double( 2 ).getClass() )&&
makeDouble( 2 ).doubleValue() == 2 &&
makeDouble( -2 ).doubleValue() == -2?
"" : "nicht ganz " )+ "richtig" ); }}
/ Übungsaufgabe
Programmieren Sie eine parameterlose Erzeugungsmethode »makePoint2D« für java.awt.geom.Point2D.Double-Objekte, die ein java.awt.geom.Point2D.Double-Objekt zurückgibt, das mit einem Erzeugungsausdruck ohne Argument erzeugt wurde.
Falls die von Ihnen geschrieben Methodendeklaration an Stelle der Ellipse »…« in den folgenden Testrahmen eingesetzt wird, sollte das sich dann ergebende Programm »richtig« ausgeben.
Main.java
public final class Main
{…
public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( ( makePoint2D().getClass().equals( new java.awt.geom.Point2D.Double().getClass() )&&
makePoint2D() != makePoint2D()?
"" : "nicht ganz " )+ "richtig" ); }}
/ Übungsaufgabe
Programmieren Sie eine Anfertigungsmethode »makePoint« mit zwei double-Parameter fuer java.awt.geom.Point2D.Double-Objekte, die ein java.awt.geom.Point2D.Double-Objekt zurückgibt, das mit einem Erzeugungsausdruck mit den der Anfertigungsmethode übergebenenen Werten als Argumentwerten erzeugt wurde.
So sollte das folgende Programm beispielsweise die darunterstehende Ausgabe erzeugen.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( makePoint( 14, 9 )); }}transcript
Point2D.Double[14.0, 9.0]
Falls die von Ihnen geschrieben Methodendeklaration an Stelle der Ellipse »…« in den folgenden Testrahmen eingesetzt wird, sollte das sich dann ergebende Programm »richtig« ausgeben.
Main.java
public final class Main
{…
public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( ( makePoint2D( 0.5, 1.5 ).getClass().equals
( new java.awt.geom.Point2D.Double().getClass() )&&
makePoint2D( 0.5, 1.5 ).getX() == 0.5&&
makePoint2D( 0.5, 1.5 ).getY() == 1.5?
"" : "nicht ganz " )+ "richtig" ); }}
/ Zusatzaufgabe
Programmieren Sie eine Erzeugungsmethode »makeSequence«, die ein Argument vom Typ »int« akzeptiert. Falls dies den Wert »0« hat, soll ein neues (leeres) java.lang.String-Objekt zurückgegeben werden und sonst ein neues (leeres) java.lang.StringBuilder-Objekt.
Falls die von Ihnen geschrieben Methodendeklaration an Stelle der Ellipse »…« in den folgenden Testrahmen eingesetzt wird, sollte das sich dann ergebende Programm »richtig« ausgeben.
Main.java
public final class Main
{…
public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( ( makeSequence( 0 ).getClass().equals
( new java.lang.String().getClass() )&&
makeSequence( 1 ).getClass().equals
( new java.lang.StringBuilder().getClass() )&&
makeSequence( 0 )!= makeSequence( 0 )&&
makeSequence( 1 )!= makeSequence( 1 )&&
makeSequence( 0 ).toString().equals( "" )&&
makeSequence( 1 ).toString().equals( "" )?
"" : "nicht ganz " )+ "richtig" ); }}
/ Übungsaufgabe
Programmieren Sie eine parameterlose Anfertigungsmethode, die ein java.util.TimeZone-Objekt liefert (um dies zu erhalten muss nicht unbedingt »new« verwendet werden), dem mit »setID( "xyz" )« die Kennung »xyz« zugeordnet wurde.
Geben Sie die Kennung dieses Objektes im Hauptprogramm aus.
/ Übungsaufgabe
Programmieren Sie eine Anfertigungsmethode, die ein java.util.TimeZone-Objekt liefert (um dies zu erhalten muss nicht unbedingt »new« verwendet werden), dem mit »setID(java.lang.String)« die Kennung zugeordnet wurde, welche der Anfertigungsmethode als Argumentwert übergeben wurde.
Geben Sie die Kennung dieses Objektes dann im Hauptprogramm aus.
Übungsaufgaben Deklaration statischer Ausgabemethoden
Im Grundkurs hatten wir gelernt, daß in Deklarationen von Methoden die Typen »int«, »double«, »java.lang.String« und – wie später behandelt wurde – auch »boolean« als Rückgabe- und Parametertypen erlaubt sind. Nun können wir dies dahingehend ergänzen, daß an Stelle der eben genannten Typen auch alle anderen Referenztypen, wie beispielsweise »java.lang.StringBuilder« zulässig sind.
Unter einer Ausgabemethode verstehen wir hier eine Methode, die einen Parameter hat und dessen Wert ausgibt. Als Name der Ausgabemethoden kann bei den folgenden Aufgaben »println« verwendet werden.
Eine Ausgabemethode für T-Objekte ist eine Ausgabemethode, die Objekte von Typ »T « akzeptiert und diese mit »println« ausgibt. Dabei soll die Antwort des Objektes auf die Nachricht »toString()« und ein Zeilenende ausgegeben werden.
/ Beispielaufgabe
Schreiben Sie eine Ausgabemethode für int-Werte!
Beispiellösung
- (Methodendeklaration)
public static void println( final int i )
{ java.lang.System.out.println( i ); }
/ Übungsaufgabe
Programmieren Sie eine Ausgabemethode für java.lang.String-Objekte!
/ Übungsaufgabe
Programmieren Sie eine Ausgabemethode für java.lang.StringBuilder-Objekte!
/ Übungsaufgabe
Programmieren Sie eine Ausgabemethode für java.awt.geom.Point2D.Double-Objekte!
/ Zusatzaufgabe
Programmieren Sie eine Ausgabemethode mit einer einzigen Methodendeklaration, die sowohl für java.lang.String-Objekte als auch für java.lang.StringBuilder-Objekte verwendet werden kann.
/ Längendrucker ←
Schreiben Sie eine Deklaration einer statischen Methode »printLength(java.lang.String)«, welche die Länge der ihr als Argument übergebenen Zeichenfolge ausgibt. (Dies ist keine Ausgabemethode im wörtlichen Sinne, aber die sie ähnelt einer Ausgabemethode.)
Übungsaufgaben Deklaration statischer identischer Methoden
Als eine „identische Methode“ bezeichnen wir hier eine Methode mit einem Parameter, die den ihr beim Aufruf übergebenen Argumentwert unverändert als Ergebnis zurückgibt. Dies kann zwar als sinnlos erscheinen, ist aber zum Üben des Schreibens einfacher Methodendeklarationen auf jeden Fall gut geeignet! Als Name der identischen Methoden kann bei den folgenden Aufgaben »id« verwendet werden.
/ Beispielaufgabe
Schreiben Sie eine identische Methode für int-Werte!
Beispiellösung
- (Methodendeklaration)
public static int id( final int i ){ return i; }
/ Übungsaufgabe
Programmieren Sie eine identische Methode für java.lang.String-Objekte!
Falls die von Ihnen geschrieben Methodendeklaration an Stelle der Ellipse »…« in den folgenden Testrahmen eingesetzt wird, sollte das sich dann ergebende Programm »richtig« ausgeben.
Main.java
public final class Main
{…
public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( ( id( "abc" )== "abc" && id( "def" )== "def" ?
"" : "nicht ganz " )+ "richtig" ); }}
/ Übungsaufgabe
Programmieren Sie eine identische Methode für java.lang.StringBuilder-Objekte!
Falls die von Ihnen geschrieben Methodendeklaration an Stelle der Ellipse »…« in den folgenden Testrahmen eingesetzt wird, sollte das sich dann ergebende Programm »richtig« ausgeben.
Main.java
public final class Main
{…
public static void main( final java.lang.String[] args )
{ final java.lang.StringBuilder builder0
= new java.lang.StringBuilder();
final java.lang.StringBuilder builder1
= new java.lang.StringBuilder();java.lang.System.out.println
( ( id( builder0 )== builder0 && id( builder1 )== builder1 ?
"" : "nicht ganz " )+ "richtig" ); }}
/ Übungsaufgabe
Programmieren Sie eine identische Methode für java.awt.geom.Point2D.Double-Objekte!
Falls die von Ihnen geschrieben Methodendeklaration an Stelle der Ellipse »…« in den folgenden Testrahmen eingesetzt wird, sollte das sich dann ergebende Programm »richtig« ausgeben.
Main.java
public final class Main
{…
public static void main( final java.lang.String[] args )
{ final java.awt.geom.Point2D.Double point0
= new java.awt.geom.Point2D.Double();
final java.awt.geom.Point2D.Double point1
= new java.awt.geom.Point2D.Double();java.lang.System.out.println
( ( id( point0 )== point0 && id( point1 )== point1 ?
"" : "nicht ganz " )+ "richtig" ); }}
/ Zusatzaufgabe
Programmieren Sie eine identische Methode, die sowohl für java.lang.String-Objekte als auch für java.lang.StringBuilder-Objekte verwendet werden kann. Dabei sollte nur eine einzige Methodendeklaration geschrieben werden.
Falls die von Ihnen geschrieben Methodendeklaration an Stelle der Ellipse »…« in den folgenden Testrahmen eingesetzt wird, sollte das sich dann ergebende Programm »richtig« ausgeben.
Main.java
public final class Main
{…
public static void main( final java.lang.String[] args )
{ final java.lang.StringBuilder builder0
= new java.lang.StringBuilder();java.lang.System.out.println
( ( id( builder0 )== builder0 && id( "abc" )== "abc" ?
"" : "nicht ganz " )+ "richtig" ); }}
Übungsaufgaben Getter
/ Getter ←
Schreiben Sie eine Deklaration einer Methode »printName« deren Parameter den Typ »java.util.logging.Logger« hat. Diese Methode soll den mit »getName()« erhaltenen Namen des Parameterobjekts und ein Zeilenende ausgeben.
Im Hauptprogramm (also in der Methode »main(java.lang.String[])«) soll dann folgendes passieren:
Es soll ein Objekt der Klasse »java.util.logging.Logger« mit dem Namen »abc« angelegt werden. (Hierfür kann kein Erzeugungsausdruck verwendet werden. Statt dessen muß eine statische Erzeugungsmethode der Klasse aufgerufen werden!)
Die Methode »printName« soll mit diesem Objekt als Argument aufgerufen werden. (Zusatzanforderung: Der Speicherplatz für dieses Objekt soll danach freigegeben werden, da es nun nicht mehr benötigt wird.)
Es soll ein weiteres Objekt der Klasse »java.util.logging.Logger« mit dem Namen »def« angelegt werden. Die Methode »printName« soll dann auch mit diesem Objekt als Argument aufgerufen werden.
Übungsaufgaben Nachrichten
/ Übungsaufgabe
Schreiben Sie eine Deklaration einer Methode mit einem Parameter »s« vom Typ »java.lang.String«. In der Methode soll diesem Parameter die Nachricht »length()« geschickt werden.
/ Übungsaufgabe
Schreiben Sie eine Deklaration einer Methode mit einem Parameter »o« vom Typ »java.lang.Object«. In der Methode soll diesem Parameter die Nachricht »getClass()« geschickt werden.