6

Here in following code we are getting value of i on a null reference, though a NPE is not there.

public class Test { static int i = 10; Test getTest() { return null; } public static void main(String args[]) { Test t = new Test(); System.out.println(t.getTest()); System.out.println(t.getTest().i); } } 

output

null 10 
2
  • Check it here : stackoverflow.com/q/21037406/1686291 Commented Jan 21, 2014 at 10:41
  • Since this can be a confusing scenario, it will actually generate a compiler warning in Eclipse: "Non-static access to a static member." Commented Jan 21, 2014 at 10:53

8 Answers 8

7

Informally speaking, you can think of this

System.out.println(t.getTest().i); 

as being equivalent to

System.out.println(Test.i); 

because i is static.

This is the simplest answer probably.

Strictly speaking, they are not equivalent. Actually
getTest() is called but its return value is not used
for accessing the i field as this test below shows.

public class Test { static int i = 10; Test getTest() { System.out.println("Method getTest() called!"); return null; } public static void main(String args[]) { Test t = new Test(); System.out.println(t.getTest()); System.out.println(t.getTest().i); } } 
Sign up to request clarification or add additional context in comments.

3 Comments

indeed.. The only logical answer is that.. But the compiler should do this during compilation itself... On finding i, it should replace t.getTest() with Test. Otherwise if t.getTest() is executed, then it returns null which cannot be used to access i... correct me if i am wrong...
see my answer, the two are not equivalent, although both access i in a static way
t.getTest() will be executed, but the result will not be used in any way.
4

i being a static variable, no instance is needed to get its value.

2 Comments

@downvoter : please comment...
Downvoter might have thought you did not answer on allowing to access a static variable value from a null object
4

The generated bytecode looks like this:

18 getstatic java.lang.System.out : java.io.PrintStream [24] 21 aload_1 [t] 22 invokevirtual experiments.Experiments.getTest() : experiments.Experiments [30] 25 pop 26 getstatic experiments.Experiments.i : int [10] 29 invokevirtual java.io.PrintStream.println(int) : void [38] 

As you see, t.getTest() is indeed called (21,22), but its result not used (25). The field i is accessed in a static way (26). Java Bytecode has no way of accessing static members via an instance. Note that this means that t.getTest().i and Test.i are not equivalent expressions! In a hypothetical syntax, the equivalent could look like this (using the semantics I'd find intuitive for this syntax:

System.out.println( {t.getTest(); return Test.i;} ); 

Note that the same holds for a field test: t.test.i is different from Test.i. Although getting the field can't have any side effects and is not a valid statement on its own, the field access could still be advised by AspectJ or something similar.

8 Comments

Are you sure that the getTest() being called is not for the first t.getTest() ?
entirely. 18 is the second getstatic java.lang.System.out in the bytecode, and the line numbers tell me the same. Besides that, the lines in the bytecode make perfect sense for coding the second println. I can clarify it if you want
No need...I trust you... :)
@SillyFreak "Note that this means that t.getTest().i and Test.i are not equivalent expressions!" - can you expand it? It's very interesting.
they are equivalent in value, but not in the code executed. As I stated, t.getTest().i does execute t.getTest(), while Test.i obviously doesn't
|
2

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.

Comments

2
 Test t = new Test(); // initialize t 

Here t isn't null as it has been initialized. Thus, you do not get a NullPointerException.

In next case where you expected a NullPointerException since t.getTest() returned null,

t.getTest().i; 

i is a static variable and you do not need to an instance to access static variables, you can just access them directly. Thus, you do not get NullPointerException here too.

And moreover,

System.out.println(i); // is an another way to access static i 

Comments

1

Static methods or variables does not need a reference to the object. You can call it even reference to the object is null.

Comments

1

To be more specific,

While accessing the Static variable, compiler will generate an getStatic instruction corresponding to that static and it will be used to access that static. thus static are instance independent they are resolved by the field/method using just an index to the run time constant pool that will be later used to solve the field reference location..

For more details refer this SO answer : https://stackoverflow.com/a/21047440/1686291

Comments

0

Simply speaking, compiler takes statics from class def, not from an object. That is why you can replace t.getTest().i with Test.i and it will be the same.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.