Implizite java.lang.Integer-Verpackung in Java
Die implizite Verpackung
Die Operation »valueOf« wird auch bei der impliziten Verpackung verwendet: Wenn ein elementarer Wert an einer Stelle verwendet wird, an der ein Objekt erwartet wird, so wird der elementare Wert in bestimmten Fällen (bei der Zuweisung und bei Argumentwerten) in ein Objekt verpackt, ohne daß dies ausdrücklich verlangt werden muß.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ final int w = 2;
final java.lang.Integer o = w; /* implizite Verpackung */
final java.lang.Integer v = 3; /* implizite Verpackung */
java.lang.System.out.println( w );
java.lang.System.out.println( o );
java.lang.System.out.println( v ); }}- Protokoll
2
2
3
Das voranstehende Programm mit impliziter Verpackung entspricht dem folgenden Programm mit expliziter Verpackng.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ final int w = 2;
final java.lang.Integer o = java.lang.Integer.valueOf( w );
final java.lang.Integer v = java.lang.Integer.valueOf( 3 );
java.lang.System.out.println( w );
java.lang.System.out.println( o );
java.lang.System.out.println( v ); }}- Protokoll
2
2
3
In dem folgenden Programm wird der int-Wert »2« an einer Stelle angegeben, an der eine Objekt-Referenz erwartet wird. Auch hier erfolgt wieder eine implizite Verpackung.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ final java.lang.Integer p = java.lang.Integer.valueOf( 4 );
java.lang.System.out.println( p.equals( 2 )); }}transcript
false
Bei der impliziten Verpackung erkennt der Übersetzer die Notwendigkeit zur Verpackung und erzeugt selbständig die notwendige Exemplarerzeugung. Dadurch entspricht der obige Quelltext dem folgenden, in dem die Operation »java.lang.Integer.valueOf(int)« verwendet wird, um ein java.lang.Integer-Exemplar mit dem Wert »2« zu erhalten.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ final java.lang.Integer p = new java.lang.Integer( 4 );
java.lang.System.out.println( p.equals( java.lang.Integer.valueOf( 2 ))); }}transcript
false
Die implizite Verpackung bewirkt also im allgemeinen keine schnellere Programmausführung als eine explizite Verpackung, sie kann jedoch das Schreiben des Quelltextes erleichtern. Außerdem ermöglicht sie es dem verwendeten Übersetzer die jeweils beste Möglichkeit zur Verpackung zu wählen: So könnte eine zukünftige Übersetzer-Version dort auch eine heute noch nicht bekannte Operation verwenden, die nicht eingesetzt werden könnte, wenn der Programmierer eine Art der Verpackung explizit verschreibt. Wenn die Art der Verpackung (z.B. mit der Exemplarerzeugung »new java.lang.Integer(int)« oder der Operation »java.lang.Integer.valueOf(int)«) egal ist, dann sollte der Programmierer also die implizite Verpackung verwenden und die Wahl der besten Möglichkeit somit dem jeweiligen Übersetzer ermöglichen.
Die implizite Verpackung tritt jedoch nicht in allen Fällen ein. In dem folgenden Beispiel könnte die Zahl »4« automatisch verpackt werden, was aber in Java nicht geschieht.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( 4.equals( 2 )); }}transcript
Main.java:3: error: malformed floating point literal
{ java.lang.System.out.println( 4.equals( 2 )); }}
^
In manchen anderen Programmiersprachen sind auch solche Schreibweisen erlaubt.
Die implizite Verpackung soll in Java einige Umständlichkeiten erleichtern, die dadurch entstehen, daß Java nicht rein objektorientiert ist. In einer reinen objektorientierten Programmiersprache gibt es gar keine elementaren Werte, so daß dort die Notwendigkeit zu einer impliziten Verpackung entfällt.
Implizite Entpackung
Falls eine Referenz auf ein Objekt der Klasse »java.lang.Integer« an einer Stelle gefunden wird, an der ein elementarer Wert erwartet wird, so wird dieser in vielen Fällen implizit entpackt.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ final java.lang.Integer o = new java.lang.Integer( 4 );
final int i = o; /* implizite Entpackung */
java.lang.System.out.println( i ); }}transcript
4
Das voranstehende Programm mit impliziter Entpackung entspricht dem folgenden Programm mit expliziter Entpackung.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ final java.lang.Integer o = new java.lang.Integer( 4 );
final int i = o.intValue();
java.lang.System.out.println( i ); }}transcript
4
Implizite Entpackung bei Operatoren
Auch wenn ein java.lang.Integer-Objekt zusammen mit einem Operator verwendet wird, der mit einem int-Operanden verwendet werden kann, erfolgt eine implizite Entpackung, außer, wenn der Operator auch mit Objekten verwendet werden kann, wie etwa beim Operator »==«. Deswegen werden beim Vergleich mit »<« die Zahlenwerte, aber beim Vergleich mit »==« die Objektreferenzen verglichen. Um das auszudrücken, was man bei Operanden vom Typ »int« mit »<« schreiben würde, kann man also auch bei Operanden vom Typ »java.lang.Integer« den Operator »<« verwenden. Will man aber das auszudrücken, was man bei Operanden vom Typ »int« mit »==« schreiben würde, muß man bei Operanden vom Typ »java.lang.Integer« den Methodennamen »equals« verwenden.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ final java.lang.Integer o = new java.lang.Integer( 3 );
final java.lang.Integer v = new java.lang.Integer( 3 );
java.lang.System.out.println( -o ); /* -3 */
java.lang.System.out.println( o + v ); /* 6 */
java.lang.System.out.println( o < v ); /* false */
java.lang.System.out.println( o == v ); /* false */
java.lang.System.out.println( o.equals( v )); /* true */ }}transcript
-3
6
false
false
true
Implizite Verpackung bei Zuweisungen
Durch die implizite Verpackung ist es möglich, einer Variablen eines geeigneten Obertyps sowohl Referenzen als auch elementare Werte zuweisen zu können.
Unsere bisherigen Regeln über Untertypen müssen erweitert werden, denn »2« hat keinen Untertyp von »java.lang.Object«, kann aber trotzdem einer Variablen dieses Typs zugewiesen werden.
Main.java
public final class Main
{public static void main( final java.lang.String[] args )
{ java.lang.Object v;
v = new java.lang.Object(); java.lang.System.out.println( v );
v = "abc"; java.lang.System.out.println( v );
v = true; java.lang.System.out.println( v );
v = 2; java.lang.System.out.println( v );
v = 2.3; java.lang.System.out.println( v ); }}transcript
java.lang.Object@15db9742
abc
true
2
2.3
Implizite Verpackung bei Parameter
Durch die implizite Verpackung ist es möglich, eine einzige Methode sowohl mit Referenzen als auch mit einem elementaren Werten aufrufen zu können.
Unsere bisherigen Regeln über Untertypen müssen erweitert werden, denn »2« hat keinen Untertyp von »java.lang.Object«, kann aber trotzdem für einen Parameter dieses Typs als Argument verwendet werden.
Main.java
public final class Main
{public static void println( final java.lang.Object value )
{ java.lang.System.out.println( value.getClass() + ": " + value ); }public static void main( final java.lang.String[] args )
{ println( new java.lang.Object() );
println( "abc" );
println( true );
println( 2 );
println( 2.3 ); }}transcript
class java.lang.Object: java.lang.Object@15db9742
class java.lang.String: abc
class java.lang.Boolean: true
class java.lang.Integer: 2
class java.lang.Double: 2.3
Übungsfragen
? Deklarationsfehler
Welche Zeilen der folgenden Quelldatei enthalten Fehler, und welche Fehler wurden gemacht?
- Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{final java.lang.Integer i = new java.lang.Integer;
final java.lang.Integer j = 0;
final int k = 0;
final java.lang.Integer l = new.java.lang.Integer( 2 );
final java.lang.Integer m = java.lang.Integer( 2 );}}