Die Nullreferenz in Java
Der spezielle Wert null ist oft erlaubt, wo eine Referenz erwartet wird, aber er ist keine Referenz auf ein Objekt
Traditionell wird der Nullwert ebenfalls als Referenz oder „Nullreferenz“ bezeichnet, obwohl er gar keine Referenz auf ein Objekt ist.
Mit dieser üblichen Sprachregelung kann man (verwirrenderweise!) sagen: Eine Referenz ist die Nullreferenz oder eine Referenz auf ein Objekt.
Bsp.: "abc"==null
Main.java
final public class Main
{ final public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( null == "Haus" ); /* false */ }}transcript
false
Wir können jetzt genauer sagen:
- Der Wert eines Exemplarerzeugungsausdrucks ist eine Referenz auf das erzeugte Objekt.
- »==« vergleicht Referenzen
o
Mathematiker können die Nullreferenz mit dem Nullvektor vergleichen: So wie der Nullvektor als einziger Vektor keine Richtung angibt, gibt die Nullreferenz als einzige Referenz kein Objekt an.
Wofür ist die Nullreferenz gut
Wenn an einer Stelle eine Referenz (auf ein Objekt) angegeben werden muß, aber kein Objekt erstellt oder gefunden werden kann, daß alle Anforderungen erfüllt, kann die Nullreferenz verwendet werden, um das Problem zu signalisieren.
- Dokumentation
- java.lang
- Class Integer
- getInteger
- public static Integer getInteger(String nm)
- Determines the integer value of the system property with the specified name.
- if the property does not have the correct numeric format, then null is returned.
Main.java
public final class Main
{public static void printIntValueFor( final java.lang.String s )
{ final java.lang.Integer i = java.lang.Integer.getInteger( s );
java.lang.System.out.println( i );
java.lang.System.out.println( i.intValue() );
java.lang.System.out.println( "println" ); }public static void main( final java.lang.String args[] )
{ printIntValueFor( "sun.arch.data.model" );
printIntValueFor( "sun.arc.data.model" ); }}Protokoll
64
64
println
null
Exception in thread "main" java.lang.NullPointerException
at Main.printIntValueFor(Main.java:7)
at Main.main(Main.java:12)Main.java
public final class Main
{public static void printIntValueFor( final java.lang.String s )
{ final java.lang.Integer i = java.lang.Integer.getInteger( s );
if( i != null )java.lang.System.out.println( i.intValue() );
else java.lang.System.err.println( "Fehler!" ); }public static void main( final java.lang.String args[] )
{ printIntValueFor( "sun.arch.data.model" );
printIntValueFor( "sun.arc.data.model" ); }}transcript
64
Fehler!
Das Nullliteral
Das Literal »null« hat als Wert eine Nullreferenz und kann an jeder Stelle verwendet werden, an der ein Ausdruck eines Referenztyps erwartet wird. Sein Typ ist der spezielle Nulltyp, der (wie ein Untertyp) in jeden anderen Referenztyp gewandelt werden kann.
Literale
Wir hatten den Begriff „Literal“ früher als Zeichenfolgenliteral, Numerale, Zeichenliteral oder Wahrheitsliteral definiert. Nun müssen wir diese Definition erweitern:
Ein Literal ist ein Zeichenfolgenliteral, ein Numerale, ein Zeichenliteral, ein Wahrheitsliteral oder das Nullliteral.
Werte
Der Begriff „Wert“ wurde früher als Oberbegriff für Zeichenfolgen, Zahlen und Wahrheitswerte eingeführt. Wir müssen ihn nun erweitern:
Ein Wert ist eine Zeichenfolge, eine Zahl, ein Zeichen, ein Wahrheitswert oder eine Referenz (einschließlich der Nullreferenz).
Bezeichner
Ein Bezeichner ist eine Bezeichnerzeichenfolge, die kein Schlüsselwort ist und keines der Literale »true«, »false« und »null« ist.
»null« ist beispielsweise eine Bezeichnerzeichenfolge, aber kein Bezeichner, da es eines der Literale »true«, »false« und »null« ist.
Referenzeffekt: Die Nullreferenz (1)
Das Wort »null« ist ein Literal, dessen Wert die Nullreferenz ist.
Die Nullreferenz ist eine Referenz, aber sie referenziert kein Objekt (sie ist keine Objektreferenz).
Die Nullreferenz kann in eine Variable eines beliebigen Referenztyps geschrieben werden.
Der Compiler könnte in den folgenden einfachen Programmen die NullPointerException vorhersehen, aber dies ist nicht immer möglich. Deswegen versucht der Compiler grundsätzlich nicht, sie zu erkennen und als Fehler zu melden.
»null« darf nicht als Bezeichner verwendet werden. (Identifier: IdentifierName but not a Keyword or BooleanLiteral or NullLiteral)
Main.java
public class Main
{ public static void main( final java.lang.String[] args )
{ final java.awt.geom.Point2D.Double o = null;
o.x = 1;
o.y = 2;
java.lang.System.out.println( o.x );
java.lang.System.out.println( o.y );
java.lang.System.out.println( "println" ); }}
Protokoll
Exception in thread "main" java.lang.NullPointerException
at Main.main(Main.java:7)- Konsole
Exception in thread "main" java.lang.NullPointerException
at Main.main(Main.java:36)
Main.java
public class Main
{ public static void main( final java.lang.String[] args )
{ final java.io.PrintStream out = null;
out.println( "alpha" );
java.lang.System.out.println( "println" ); }}
Protokoll
Exception in thread "main" java.lang.NullPointerException
at Main.main(Main.java:7)- Konsole
Exception in thread "main" java.lang.NullPointerException
at Main.main(Main.java:36)
Die Laufzeitprüfung ⁺
Hier wird der Zieltyp (beziehungsweise, ob überhaupt ein Objekt vorhanden ist) erst zur Laufzeit geprüft.
Main.java
public class Main
{ public static void m( final java.lang.Object s )
{ java.lang.System.out.println( s.getClass() ); }public static void main( final java.lang.String[] args )
{ m( new java.lang.String( "abc" )); /* keine Compiler-Fehlermeldung */
m( null ); /* keine Compiler-Fehlermeldung */
java.lang.System.out.println( "println" ); }}Protokoll
class java.lang.String
Exception in thread "main" java.lang.NullPointerException
at Main.m(Main.java:3)
at Main.main(Main.java:7)
Ausgabe von »null«
Mit dem Namen »java.lang.System.out.println« kann man so ziemlich alles ausgeben – außer »null«!
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( null ); }}transcript
Main.java:3: error: reference to println is ambiguous
{ java.lang.System.out.println( null ); }}
^
both method println(char[]) in PrintStream and method println(String) in PrintStream match
1 error
Dies liegt daran, daß es keine spezielle Überladung für den Typ von »null« gibt, so daß eine Überladung mit einem Obertyp aufgerufen werden muß. Da hier aber mehrere Überladungen gleichermaßen in Frage kommen, kann der Compiler sich nicht für eine entscheiden.
Die Fehlermeldung verschwindet, wenn man einen Ausdruck mit dem Wert »null« verwendet, der einen anderen Typ als den des Ausdrucks »null« hat.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ final java.lang.String nullString = null;
java.lang.System.out.println( nullString ); }}transcript
null
Semikolon ⁺
Häufige Fehler in Java-Büchern: „Man muß import verwenden, um eine Bibliothek benutzen zu können“, „statische innere Klassen“, und „jede Anweisung endet mit einem Semikolon“. Wo ist das Semikolon der beiden Anweisungen des folgenden Programms?
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ while( java.lang.System.out.printf( "Hallo " )== null ){}
while( java.lang.System.out.printf( "Welt!%n" )== null ){} }}transcript
Hallo Welt!
»java.lang.System.out.printf(java.lang.String)« gibt eine Referenz zurück, die oben mit der Nullreferenz verglichen wird.