First to clarify "Reference Variable" type:
Object obj;
Points to nothing and the Reference Variable obj would have NO type.
Now
Object obj = new String();
System.out.println(obj.getClass());//prints class java.lang.String
obj points to a String and the Reference Variable obj has type String.
The point is Java is a statically typed language and all reference type variables have a type assigned at compile time. The reference variable obj can point to some other object as long as it is a subclass of Object. In this case
almost anything. Consider
Object obj = new String();
System.out.println(obj.getClass());//prints class java.lang.String
Number num = new Byte((byte)9);
obj = num;
System.out.println(obj.getClass());//prints class java.lang.Byte
At Runtime, same as compile time, the reference variable obj has type Byte.
The static/dynamic type of an object, for me, has to do with inheritance.
More specifically the overriding mechanism. Also known as Dynamic Polymorphism
and Late Binding.
Consider overriding the equals() in class Object:
public class Types {
@Override
public boolean equals(Object obj){
System.out.println("in class Types equals()");
return false;//Shut-up compiler!
}
public static void main(String[] args){
Object typ = new Types();
typ.equals("Hi");//can do this as String is a subclass of Object
}
}
Now we know that the type of the reference variable typ is Types.
Object typ = new Types();
When it comes to
typ.equals("Hi");
This is how I think the compiler thinks.
If the equals() is
1.NOT static and final, which it is.
2.Referenced from a base class (more on this soon).
then the compiler defers which method gets called to the JVM. The exact method that is invoked depends on the Dynamic Type(more soon) of the variable that calls the method. In our case the reference variable is typ.
This is known as Dynamic Method Invocation.
Now Referenced from a base class:
From the above code
Object typ = new Types();
typ.equals("Hi");
Type Object could be regarded as the base type of typ, also known as the Static Type of a reference variable and the equals() is referenced from the base type, in this case Object.
if we had
Types typ = new Types();
There would be no reference from a base type and hence no Dynamic Method Invocation.
Now to the Dynamic Type of a reference variable.
Object typ = new Types();
typ.equals("Hi");
The Dynamic Type of typ is Types and according to Dynamic Method Invocation, the equals() in class Types would be called at runtime.
Also lets say we had another class that extends Types, TypesSubClass.
And TypesSubClass also had a overridden equals(). Then
Object typ = new TypesSubClass();
typ.equals("Hi");
Would make the Dynamic Type of typ TypesSubClass and TypesSubClass's
equals() would be called at runtime.
To be honest, I personally didn't know why we needed all of this and have posted a question regarding this. check
What is the reason behind Dynamic Method Resolution in a staticlly typed language like Java