Search code examples
javainheritancecompilationoverridingexecution

How does java compiler choose correct methods and variables in inheritance


I am a bit confused when inheritance and type casting is mixed. I want to understand the rules which java compiler follows when choosing correct methods and variables in inheritance.

I have read something like

Variables are bound at compile time and methods are bound at run time.

The second one is from stackoverflow (@John Skeet)

Overload resolution (which method signature is called) is determined at compile-time, based on the compile-time types of both the method target and the argument expressions

The implementation of that method signature (overriding) is based on the actual type of the target object at execution time.

But the problem is that they are explanations of specific situations and do not give the general process to be followed when other factors (like exception handling) are taken into consideration.

This may be bad practice but assume that both methods and variables are overridden(hidden in case of static variables).

Now if java compiler has to choose at compile time which method/variable needs to be invoked then what algorithm will it follow? Similarly at run time what is the algorithm that java compiler will use(based on the actual type of the object whose reference is being used)?


Solution

  • All method signatures and variables are verified during compile-time but the actual method calls are done / resolved during run-time.

    For example :

    class A {
    int i=5;
    public void doSomething(){
    //print "in A"
    }
    }
    
    class B extends A{
    int i=10;    
    public void doSomething(){
    // print "in B"
    }
    
    public static void main(String[] args){
    A a = new B();
    a.doSomething();
    }
    }
    

    Now, when you call a.doSomething(); , during compilation, the compiler just checks whether doSomething() is defined for class A (lhs reference). It is not even bothered about whether the method is also defined for class B. Even if the method were not present in B, the program would compile fine.

    Next, during runtime, the JVM dynamically decides which method to call based on type of Object (B in your case.).

    So, "in B" is printed.

    Now, coming back to fields. Access to fields are resolved during compile time. So, if a field doesn't exist during compile-time, then the compilation fails. The fields are called based on the reference type. So, a.i will print 5 (A's value of i) because the field was resolved during compile-time. Thus, the difference is, method calls are resolved during runtime, their signatures are needed / checked during compile-time where-as fields are checked / resolved during compile-time.