views:

603

answers:

8

Given a class "Bar" that extends class "Foo" which implements interface "DeeDum"

public interface DeeDum {
    public String getDee();
    public String getDum();
}

public class Foo implements DeeDum {
    public String dee = "D";
    public String dum;

    public String getDee() { return dee; }
    public String getDum() { return dum; }
}

public class Bar extends Foo {
    public String dee = "DEE";
    public String dum = "DUM";
}

Why doesn't this work?

public static Bar mybar = new Bar();
Assert.assertEquals("DEE", mybar.getDee());
Assert.assertEquals("DUM", mybar.getDum());

I get "D" and null instead. In other words, Bar doesn't inherit accessors from Foo, and can't override properties. Somehow calling mybar.getDum() calls a static instance of class Foo and returns the static properties from the parent class. Even if the properties are overridden in the child class! Does that mean that you can't inherit any methods or properties?

I can't wrap my head around it. Why can't Java inherit accessors (and why did they choose such an odd alternative?)

Or am I just doing something wrong?

+2  A: 

Accessor methods themselves (e.g. getDee()) are inherited, but instance variables are not.

If instance variables could be overridden in subclasses (like you're trying to do here), it would cause many more problems than it would fix.

Michael Myers
this is what I'm trying to figure out. What problems would it cause?
and what about static variables?
Hmm, it occurs to me that the answer I was going to give was somewhere between "you shouldn't do that" and "why would you want to do that?" So pardon me while I go search for references. :)
Michael Myers
+9  A: 

You are hiding the inherited variables with ones defined in the subclass.

public class Bar extends Foo {
    public Bar() {
        dee = "DEE";
        dum = "DUM";
    }
}

should work better.

iny
+13  A: 

The problem is that your duplicate declaration of the members dee and dum of Foo in Bar hides those of Foo. Bar has its own members; those of Foo will never be used by Bar. What you mean is something like

public class Bar extends Foo {
  {
    dee = "DEE";
    dum = "DUM";
  }
}
Arne Burmeister
Quite the opposite. His problem is that he *doesn't* override them - he *hides* them.
Draemon
yes, bad example. I was trying to code a simplistic example to the "Eclipse compiler" -- get rid of all the icons in the trough and assume it's correct.
for my next trick, I'll try to learn Spanish by writing an essay on "Why Unicorns are cooler than Griffons" in MS Word, and let clippy correct my spelling and grammar.
+1  A: 

Accessors aren't the problem, it's the fields. The accessors are referring to Foo.this.dee, not to Bar.this.dee which are separate.

sblundy
+5  A: 

When you call mybar.getDee(), you're calling the method defined in the Foo base class. (That method was inherited by Bar. Otherwise, you wouldn't have been allowed to call it on a Bar instance variable in the first place.) That method returns the value of the dee field, but it's the dee field defined in the Foo class — the class where the method itself was defined. The compiler resolved the reference to the field at the time the method was compiled, in the Foo class.

Some other answers have used the word override to define what you did by declaring a field named dee in Bar, but that's not what happened. You can't override a field because fields aren't virtual. Perhaps you thought they were, though. If there were such a thing as a "virtual field," I too might expect getDee() to return the run-time class's version of the field (the one in Bar) instead of the one that was in scope at the time the method was compiled (Foo's). But that's simply not the way Java (or C#, or C++, or Delphi, or any other language I know of) works. What language are you accustomed to where this would have worked?

Rob Kennedy
A: 

Thanks to all for helping me understand and see my simple error. I find an arrogant posture initially helps me to be more humble and quicker to accept correction.

A: 

Actually, I'm seeing something weird and undeterministic still. If you have another class 'Bar' that extends Foo and sets the inherited accessors in an initialization block

While you can set the parent property in the above block, it doesn’t actually create a copy for the child class.

It seems to be a non-deterministic initialization for multiple classes.

So if you have Bar and Baz which both extend foo and have an initialization block, it seems like both inherit the value set by Bar.

public class Bar extends Foo {
    {
        dee = "dee";
        dum = "dum";
    }
}
public class Baz extends Foo {
    {
        dee = "DEE";
        dum = "DUM";
    }
}

public static Bar bar = new Bar();
public static Baz baz = new Baz();

System.out.println("mybaz: " + mybaz.getDee() + mybaz.getDum());  // DEEDUM
System.out.println("mybar: " + mybar.getDee() + mybar.getDum());  // DEEDUM

but if they're instantiated in a different order, I get:

public static Baz baz = new Baz();
public static Bar bar = new Bar();

System.out.println("mybaz: " + mybaz.getDee() + mybaz.getDum());  // deedum
System.out.println("mybar: " + mybar.getDee() + mybar.getDum());  // deedum

And it comes out still differently if a default is set in the base class Foo.

I think I understand now that the initialization block in Bar and Baz is actually setting Foo::dee and Foo::dum, but why the difference in declaration? Seems "undefined" to me.

You're sure dee and dum aren't static variables in Foo?
Michael Myers
+1  A: 

As for your second "question"...

Actually, I'm seeing something weird and undeterministic still...

...

"...System.out.println(baz.getDee()); // 'DEE' but would expect 'dee'"

It would be useful if you run the program before posting the question to see actual results.

This is what I get. It is "dee" as you expected.

You could see it for your self by creating the files, compiling them and the run them as shown below:

C:\oreyes\samples\java\dee>type DeeDum.java Foo.java Bar.java Baz.java Test.java

DeeDum.java


public interface DeeDum {
    public String getDee();
    public String getDum();
}

Foo.java


public class Foo implements DeeDum {
    public String dee = "D";
    public String dum;

    public String getDee() { return dee; }
    public String getDum() { return dum; }
}

Bar.java


public class Bar extends Foo {
    {
        dee = "DEE";
        dum = "DUM";
    }
}

Baz.java


public class Baz extends Foo {
    {
        dee = "dee";
        dum = "dum";
    }
}


Test.java


class Test {
    public static Bar bar = new Bar();
    public static Baz baz = new Baz();
    public static void main( String [] args ) {
        System.out.println(bar.getDee()); // 'DEE'
        System.out.println(baz.getDee()); // 'DEE' but would expect 'dee'
    }
}

C:\oreyes\samples\java\dee>javac *.java

C:\oreyes\samples\java\dee>java Test
DEE
dee

C:\oreyes\samples\java\dee>

PEBKAC?

OscarRyz