The following simple code snippet is working fine and is accessing a static field with a null object.
final class TestNull
{
public static int field=100;
public TestNull temp()
{
return(null);
}
}
public class Main
{
public static void main(String[] args)
{
System.out.println(new TestNull().temp().field);
}
}
In the above code, the statement System.out.println(new TestNull().temp().field); in which the static field field is being associated with a NULL objectnew TestNull().temp(), still it is returning a correct value of it which is 100 instead of throwing a null pointer exception in Java! Why?
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
Static variables are shared among every object of a class. So while the actual object reference you are returning is null (In C++: TestNull* temp = null;), you have an object of type TestNull which Java can use to find static values of that class.
Remember in Java objects are really pointers. Pointers have a type. From that type Java can discern certain information, even if its pointing to null.
Static fields are associated with the class not an instance of that class. Therefore you don't need an instance of an object to access the static field.
You could also access the field by calling TestNull.field
Related
The following simple code snippet is working fine and is accessing a static field with a null object.
final class TestNull
{
public static int field=100;
public TestNull temp()
{
return(null);
}
}
public class Main
{
public static void main(String[] args)
{
System.out.println(new TestNull().temp().field);
}
}
In the above code, the statement System.out.println(new TestNull().temp().field); in which the static field field is being associated with a NULL objectnew TestNull().temp(), still it is returning a correct value of it which is 100 instead of throwing a null pointer exception in Java! Why?
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
Static variables are shared among every object of a class. So while the actual object reference you are returning is null (In C++: TestNull* temp = null;), you have an object of type TestNull which Java can use to find static values of that class.
Remember in Java objects are really pointers. Pointers have a type. From that type Java can discern certain information, even if its pointing to null.
Static fields are associated with the class not an instance of that class. Therefore you don't need an instance of an object to access the static field.
You could also access the field by calling TestNull.field
Given the following enum:
enum Repeat {
Daily,
Weekly,
Yearly
}
I realize we are able to write it this way:
Repeat repeat = Repeat.Daily.Weekly.Yearly.Weekly;
which is equivalent to:
Repeat repeat = Repeat.Weekly;
May I know why such syntax is allowed? Is there a way to let the compiler warn us against this?
This is allowed as Daily, Weekly, Yearly are the static field by default inside the enum and holds the object of Repeat. Also, you will get a warning from the compiler "The static field Repeat.Weekly should be accessed in a static way". It is similar to below lines of code.
class Foo{
public static Foo obj1 = new Foo();
public static Foo obj2 = new Foo();
public static Foo obj3 = new Foo();
}
Foo f = Foo.obj1.obj2.obj3; // will work fine but you will get a warning from the compiler.
Here is some part of bytecode inspection of Repeat enum and from this, it is clear that Enum variable is static and holds the Object of Enum itself.
0: new #1 // class com/java8/demo/Repeat
3: dup
4: ldc #14 // String Daily
6: iconst_0
7: invokespecial #15 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #19 // Field Daily:Lcom/java8/demo/Repeat;
13: new #1 // class com/java8/demo/Repeat
Enum instance are just static instance of the enum class.
We have two way to access static field of a class:
Via class itselft: Repeat.Daily
Via instance of class: Repeat.Daily.Daily
When you chain your enum:
Repeat repeat = Repeat.Daily.Weekly.Yearly.Weekly;
It's just like get a static field from an instance of a class.
Is there a way to let compiler warn us against this?
Yes, use a good IDE and turn on warning. That way, you'll be notified as soon as your write the code, before you even compile it.
E.g. in Eclipse, it is called "Non-static access to static member":
Enum literals are static members, and with each static member, one can access them either using the class reference:
TypeName.staticMember
TypeName.staticMethod()
Or on an instance:
new TypeName().staticMember
new TypeName().staticMethod()
The second approach is discouraged (and the compiler will issue a warning)
As enum literals are just static members, Repeat.Daily.Weekly.Yearly.Weekly is like the second code snippet above, accessing static members on instance references.
With a class, that would be:
class Type {
static Type INSTANCE1, INSTANCE2, INSTANCE3;
}
And one can get a reference to INSTANCE3 using Type.INSTANCE1.INSTANCE2.INSTANCE3. It's valid, but it's bad practice.
I've come across a weird thing while learning Java. Consider the following program:
public class GetClassNameInheritance {
public static void main(String[] args) {
Employee e = new Employee();
Person p = (Person) e;
System.out.println(p.getClass());
}
}
class Person {
}
class Employee extends Person {
}
I was expecting the output to be Person because of the cast, but it is Employee! Honestly, I'm stumped and can't find an explanation. The official Oracle tutorial doesn't mention this behavior, and the docs seem too terse to be helpful. I can make out from other StackOverflow examples that this is something to do with "runtime class" but I don't understand the underlying idea. Can someone explain what's going on here?
In Java, Type casting does not change the type of object. Once an Employee, your object is always an Employee. Type casts do not work like in other languages such as C/C++.
Though the p reference is of type Person, it is in fact referring to an object of type Employee in the JVM heap. When you invoke the p.getClass() method, the reference in turn invokes the method on the object and not on the reference. That's the reason you see Employee in your output.
The only type of casts that would work is the one that you can perform on primitives.
int x = (int)2.5f;
The return value will be type cast to int.
You can read more about type casts and conversions here:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html
http://www.wideskills.com/java-tutorial/java-object-typecasting
Well let's look what happens when the main method is compiled:
0: new #2 // class Employee
3: dup
4: invokespecial #3 // Method Employee (Constructor)
7: astore_1 // Save local variable "e"
8: aload_1 // Load local variable "e"
9: astore_2 // Save to local variable "p"
10: getstatic #4 // Field System.out PrintStream;
13: aload_2 // Load local variable "p"
14: invokevirtual #5 // Method Object.getClass()
17: invokevirtual #6 // Method PrintStream.println(Object)
And if we were to look at a decompiler's interpretation of this bytecode:
public static void main(String[] args) {
Employee e = new Employee();
System.out.println(e.getClass());
}
The compiler has "optimized" the code which results in your cast being removed since it was deemed unnecessary. Anacron's answer explains why the compiler deemed it unnecessary.
If you want to know the super class of current class, you can use
p.getClass().getSuperclass() //returns person.
From the docs
getClass() always returns the runtime class of this Object. The returned Class object is the object that is locked by static synchronized methods of the represented class.
And a runtime class is one which has been instantiated with the constructor call.
Actually, if you will see, here Person p = (Person) e; the cast is not needed, you can always assign a derived class object to a base class.
For Example
List<String> list = new ArrayList<>();
Above will not throw an error.
I'm little confused about static methods and object creation in java.
As we know we can access static members in static method as here.
public static void main(String[] args){
// only static method from outside ( without any object )
}
But my stupid question is that why java allow this?
`public static void main(String[] args){
Object o = new Object(); // is constructor implicitly static?
// I'm sure no but why java allow this to call here?
}
I know the above statement is similar to declare local variable in static method.
public static void main(String[] args){
int a = 3;
}
But I'm little confused about constructor.
In bytecode, your main() method looks like this (result of the javap -c Main.class command):
public static void main(java.lang.String[]);
Code:
0: new #3 // class java/lang/Object
3: dup
4: invokespecial #8 // Method java/lang/Object."<init>":()V
7: astore_1
8: return
As you can see, at location 0, the new instruction is performed. Then, at location 4, the constructor is invoked on the newly created object.
This is also specified in the Java Virtual Machine Specification:
4.10.2.4. Instance Initialization Methods and Newly Created Objects
Creating a new class instance is a multistep process. The statement:
...
new myClass(i, j, k);
...
can be implemented by the following:
...
new #1 // Allocate uninitialized space for myClass
dup // Duplicate object on the operand stack
iload_1 // Push i
iload_2 // Push j
iload_3 // Push k
invokespecial #5 // Invoke myClass.<init>
...
Constructors are not static. They are called on the instance, you just created. In byte code what happens.
An new object is created, but it is not inilialised.
The constructor is called on that object. In the constructor this is the object being initialised.
How do static methods actually run in Java? We usually invoke them using the class name, and do not create any object for them, but these are objects which actually can "run", not methods!
For static methods, a special keyword is available and added as part of the byte-code. It is called invokestatic.
From Oracle docs :
invokestatic
Operation
Invoke a class (static) method
Description :
The unsigned indexbyte1 and indexbyte2 are used to construct an index
into the run-time constant pool of the current class (§2.6), where the
value of the index is (indexbyte1 << 8) | indexbyte2. The run-time
constant pool item at that index must be a symbolic reference to a
method (§5.1), which gives the name and descriptor (§4.3.3) of the
method as well as a symbolic reference to the class in which the
method is to be found. The named method is resolved (§5.4.3.3). The
resolved method must not be an instance initialization method (§2.9)
or the class or interface initialization method (§2.9). It must be
static, and therefore cannot be abstract.
On successful resolution of the method, the class that declared the
resolved method is initialized (§5.5) if that class has not already
been initialized.
The operand stack must contain nargs argument values, where the
number, type, and order of the values must be consistent with the
descriptor of the resolved method.
Sample code :
public class Example {
static void myStaticMethod() {
System.out.println("Hello");
}
public static void main(String[] args) {
myStaticMethod();
}
}
Byte code :
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=0, locals=1, args_size=1
0: invokestatic #31 // Method myStaticMethod:()V
3: return
LineNumberTable:
line 8: 0
line 9: 3
LocalVariableTable:
Start Length Slot Name Signature
0 4 0 args [Ljava/lang/String;
Runtime constant pool of class :
...
#31 = Methodref #1.#32 // Example.myStaticMethod:()V
...
In case of static method Java loads the method when the class is loaded and shares the method with all the objects also and that's why an object is not necessary.
It's not always necessary to have an object in order to run a method.
And no, it's not the object that runs. It's the method that does the operation and objects or classes hold them as a property.