Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java "trick", redefining daughter class member

I'm training for a Java exam, and I've come across something I don't understand in last year subject. Here is the code

class Mother {
    int var = 2;

    int getVar() {
        return var;
    }
}

class Daughter extends Mother {
    int var = 1;

    int getVar() { 
        return var;
    }

    public static void main(String[] args) {
        Mother m = new Mother();
        System.out.println(m.var);
        System.out.println(m.getVar());
        m = new Daughter();
        System.out.println(m.var);
        System.out.println(m.getVar());
    }
}

The question is "what is the output of this program?". I would have go with 2 2 1 1, but when compiling and running this piece of code, I get 2 2 2 1.

Anyone can explain me why ?

Thanks for reading !

like image 289
ksol Avatar asked May 15 '11 12:05

ksol


1 Answers

The method call m.getVar() is a virtual method call. The second time you call it, it's dynamically dispatched to the derived Daughter.getVar(), which does what you expect (accesses Daugther.var and returns that).

There is no such virtual dispatch mechanism for member fields. So m.var always refers to Mother.var, i.e. the base class's version of that variable.

The Daughter class can be seen as having two different var member: the one from Mother and its own. Its own member "hides" the one in Mother, but can be accessed from within the Daughter class by using super.var.

The official spec for this is in section 8.3 Field Declarations of the JLS. Quote:

If the class declares a field with a certain name, then the declaration of that field is said to hide any and all accessible declarations of fields with the same name in superclasses, and superinterfaces of the class. The field declaration also shadows (§6.3.1) declarations of any accessible fields in enclosing classes or interfaces, and any local variables, formal method parameters, and exception handler parameters with the same name in any enclosing blocks.

Note that it can get pretty interesting (emphasis added):

If a field declaration hides the declaration of another field, the two fields need not have the same type.

And:

There might be several paths by which the same field declaration might be inherited from an interface. In such a situation, the field is considered to be inherited only once, and it may be referred to by its simple name without ambiguity.

So that paragraph is well worth reading :-)

like image 159
Mat Avatar answered Oct 08 '22 17:10

Mat