简体   繁体   中英

In Java, why would a variable declared in both a parent and child class be invisible in an instance of the child class?

Specifically, why would a variable declared in both a parent and child class be invisible in an instance of the child class passed to a method where the argument is the parent class?

Here is a simplified example of an issue that's puzzling me. There are three classes, a parent and two child subtypes. The classes have a Foo object as a field and this static sort of factory method:

class Parent {
    public Foo myFoo;

    public static ThinChild createThinChild(Foo someFoo) {
        ThinChild thinChild = new ThinChild(someFoo);
        return thinChild;
    }

    public Foo getFoo() {
        return myFoo;
    }
}

class ThinChild extends Parent {
    public Foo myFoo;

    public ThinChild(Foo someFoo) {
        myFoo = someFoo;
    }
}

class ThickChild extends Parent {
    public Foo myFoo;

    public ThickChild(Foo someFoo) {
        myFoo = someFoo;
    }
}

Now consider this handler class:

class ChildHandler {
    private void doSomethingToThinChild(ThinChild thinChild) {
        assert(thinChild.getFoo() != null);
        doSomethingToAllChildren(thinChild);
    }

    private void doSomethingToAllChildren(Parent thinOrThickChild) {
        assert(thinOrThickChild.getFoo() != null);
    }
}

When I call doSomethingToThinChild , the assert passes. But in the method doSomethingToAllChildren , the assert fails. This is not what I expect.

Moreover, if I add the same exact getFoo method that's in the Parent class to my ThinChild class, the assert now works. Which solves my immediate problem but seems undesirable to me insofar as I'm now maintaining identical code in each of the child classes where I'd prefer just to maintain it in the parent.

My actual case is a bit more complicated, but I hope I've captured all the relevant details. Assuming that I have, is there any explanation for why this would be expected behavior?

It is possible that there's an additional complication in my actual code that I haven't represented here. But I'd first like to confirm that my understanding of class inheritance in Java is sound.

Thanks.

Remove public Foo myFoo . In nested classes, this field extends from parent class. You can't change it because you have 2 variables with same name. So JVM initialized the variable with the smaller scope.

Also the good way is to create constructor in parent:

public Parent(Foo someFoo) {
    myFoo = someFoo;
}

and then call it in subclasses:

public ThinChild(Foo someFoo) {
    super(someFoo);
}

myFoo is visible from direct child classes, you just have to qualify it with a "super.myFoo". This only works going 1 level up the chain though. so if ThinChild had a subclass ThinnerChild with a myFoo as well, you could not get to instance of "myFoo" which lives in the Parent class. The idea being that you should be able to override your own behavior with your parents, but you should not be able to override your parent (hence why something like super.super is not allowed).

That being said, removing the instances on the child class is most likely what you want, since each ThinChild and ThickChild effectively has two "myFoo" instances in this case, one belonging to it, and one to it's parent.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM