Static fields on a null reference in Java
That behaviour is specified in the Java Language Specification:
a null reference may be used to access a class (static) variable without causing an exception.
In more details, a static field evaluation, such as Primary.staticField
works as follows (emphasis mine) - in your case, Primary = main.getNull()
:
- The Primary expression is evaluated, and the result is discarded. [...]
- If the field is a non-blank final field, then the result is the value of the specified class variable in the class or interface that is the type of the Primary expression. [...]
Accessing a static field with a NULL object in Java
As opposed to regular member variables, static variables belong to the class and not to the instances of the class. The reason it works is thus simply because you don't need an instance in order to access a static field.
In fact I'd say it would me more surprising if accessing a static field could ever throw a NullPointerException
.
If you're curious, here's the bytecode looks for your program:
// Create TestNull object
3: new #3; //class TestNull
6: dup
7: invokespecial #4; //Method TestNull."<init>":()V
// Invoke the temp method
10: invokevirtual #5; //Method TestNull.temp:()LTestNull;
// Discard the result of the call to temp.
13: pop
// Load the content of the static field.
14: getstatic #6; //Field TestNull.field:I
This is described in the Java Language Specification, Section 15.11.1: Field Access Using a Primary. They even provide an example:
The following example demonstrates that a null reference may be used to access a class (static) variable without causing an exception:
class Test {
static String mountain = "Chocorua";
static Test favorite(){
System.out.print("Mount ");
return null;
}
public static void main(String[] args) {
System.out.println(favorite().mountain);
}
}
It compiles, executes, and prints:
Mount Chocorua
Why does Java compiler allow static variable access through null object?
To add some additional info to the current answers, if you disassemble your class file using:
javap -c TestClass1
You'll get:
Compiled from "TestClass1.java"
public class TestClass1 extends java.lang.Object{
static int a;
public TestClass1();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: aconst_null
1: astore_1
2: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
5: aload_1
6: pop
7: getstatic #3; //Field a:I
10: invokevirtual #4; //Method java/io/PrintStream.println:(I)V
13: return
static {};
Code:
0: bipush 10
2: putstatic #3; //Field a:I
5: return
}
Here you can see that the access to the static field is done in line 7 by the getstatc
instruction. Whenever a static field is accessed through code, a corresponding getstatic
instruction will be generated in the .class
program file.
*static
instructions have the particularity that they don't requiere a reference to the object instance to be in the stack prior to calling them (like, for example invokevirtual which does require an object ref in the stack), they resolve the field/method using just an index to the run time constant pool that will be later used to solve the field reference location.
That's a technical reason for the warning "The static field should be accessed in a static way" that some IDEs will throw at you when you write t1.a
, because the object instance is unnecessary to resolve the static field.
Call static method on null object
Accessing a static method or variable can be done via a null reference for the class that contains that static method/variable.
Since name
is static, getFoo().name
has the same result as Foo.name
or just name
, regardless of whether or not getFoo()
returns null
.
However, it is always better to use the class name when accessing a static method/variable, since it makes it clear that you intended to access a static member.
How static fields are referenced through objects?
The instance is in fact not used. Java uses the type of the variable, and then reads the static (class) field.
That's why even a null with the correct type won't raise a null pointer exception.
Try this:
Foo foo1 = null;
int valFromObject = foo1.statValue; //will work
Or this:
int valFromNull = ((Foo)null).statValue; //same thing
Accessing static class members through instances is discouraged for obvious reasons (the most important being the illusion that an instance member is being referenced, in my opinion). Java lets use foo1.statValue
, with a warning ("The static field Foo.statValue should be accessed in a static way"
as reported by my IDE).
Why not a NullPointerException while accessing static with null reference?
From Java Language Specifications
Receiver Variable Is Irrelevant For static Field Access
The following program demonstrates that a null reference may be used to access a class (static) variable without causing an exception:
class Test3 {
static String mountain = "Chocorua";
static Test3 favorite(){
System.out.print("Mount ");
return null;
}
public static void main(String[] args) {
System.out.println(favorite().mountain);
}
}
It compiles, executes, and prints:
Mount Chocorua
Even though the result of favorite() is null, a NullPointerException is not thrown. That "Mount " is printed demonstrates that the Primary expression is indeed fully evaluated at run time, despite the fact that only its type, not its value, is used to determine which field to access (because the field mountain is static).
Implies even though primary expression (Here is instance) is evaluated at run time, but its value is discarded and only its type is considered.
Related Topics
What's Alternative to Singleton
Populating Spring @Value During Unit Test
Parsing JSON in Java Without Knowing JSON Format
How to Hot-Reload Properties in Java Ee and Spring Boot
Bytebuffer.Allocate() VS. Bytebuffer.Allocatedirect()
How to Write Logs in Text File When Using Java.Util.Logging.Logger
Singleton with Arguments in Java
Increasing the Jvm Maximum Heap Size for Memory Intensive Applications
Is There a Fixed Sized Queue Which Removes Excessive Elements
How to Create 2 Separate Log Files with One Log4J Config File
Filter Jacoco Coverage Reports with Gradle