javaoverridingmember-hiding

Instance method overiding vs Field hiding


Below is the code,

package ClassesOverridingHidingAccess;

interface I{
    int x = 0;
}
class T1 implements I{
    int x = 1;
    String s(){
        return "1";
    }
}

class T2 extends T1{
    int x  = 2;
    String s(){
        return "2";
    }
}

class T3 extends T2{
    int x = 3;
    String s(){
        return "3";
    }

    void test(){
        // Accessing instanc method
        System.out.println("s()=\t\t" + s());   // 3
        System.out.println("super.s()=\t" + super.s()); // 2
        System.out.println("((T2)this).s()= " + ((T2)this).s());  // 3; method is resolved at runtime
        System.out.println("((T1)this).s()= " + ((T1)this).s());  // 3; method is resolved at runtime

        //Accessing instance attribute
        System.out.println("\n\nx=\t\t" + x);  // 3
        System.out.println("super.x=\t" + super.x);  // 2
        System.out.println("((T2)this).x=\t" + ((T2)this).x);  // 2; resolved at compile time
        System.out.println("((T1)this).x=\t" + ((T1)this).x);  // 1; resolved at compile time
        System.out.println("((I)this).x=\t" + ((I)this).x);   // 0; resolved at compile time
    }
}

public class SuperAndInstanceMethods {
    public static void main(String[] args) {
        (new T3()).test();
    }
}

where,

it is the run time class, which counts in case of instance method access.

it is the view of an object, which counts in case of field access.

Casting does not change object's class type. I mean ((T1)this) instanceof T3 is true, if this points to object of type T3.

So, What is the rationale behind the rule followed for field access? Rule for instance methods make sense to me.

Note: For me, it is an overhead to remember these rules unless there is a proper reason.


Solution

  • Instance Method's are resolved via a V-table, that is how the runtime type's method are invoked. There is no such table enabling this for fields (or static methods for that matter), so the compile time type is used.

    Hiding fields and then doing this kind of stuff ((T1)this).x is very unusual, I would avoid it as I don't think it's readable.

    And the java docs confirms:

    Within a class, a field that has the same name as a field in the superclass hides the superclass's field, even if their types are different. Within the subclass, the field in the superclass cannot be referenced by its simple name. Instead, the field must be accessed through super, which is covered in the next section. Generally speaking, we don't recommend hiding fields as it makes code difficult to read.

    (Emphasis mine)

    So it should be low on your list of rules to remember.

    You can turn on a error/warning for this in all good IDE's, here it is in IntelliJ:

    IntelliJ inspection