hdx
hdx

Reputation: 4558

Java Inheritance Question

I Have something similar to this setup:

public class Base {
    public String getApple() {return "base apple"};
}

public class Extended extends Base{
    public String getApple() {return "extended apple"};
}

Somewhere else in the code I have this:

{
    Base b = info.getForm();

    if (b instanceof Extended){
        b = (Extended) b;
    }

    System.out.println(b.getApple()); // returns "base apple" even when if clause is true why??

}

How do I accomplish that?

Upvotes: 1

Views: 1177

Answers (8)

Peter
Peter

Reputation: 8575

Are you sure your code example provided in your question EXACTLY matches the code your are using? The reason I ask is that the behavior you are describing happens when you access a public FIELD instead of a public METHOD with an object pointer.

For example:

public class BaseClass {
    public String baseField;

    public BaseClass() {
        baseField = "base";
    }

    public String getBaseField() {
        return baseField;
    }
}

public class SubClass extends BaseClass {
    public String baseField;

    public SubClass () {
        baseField = "sub";
    }

    public String getBaseField() {
        return baseField;
    }
}

public class MainClass {
    public static void main(String[] args) {
        BaseClass baseObject = new BaseClass();
        SubClass subObject = new SubClass();
        System.out.println(baseObject.getBaseField());
        System.out.println(subObject.getBaseField());
        System.out.println(baseObject.baseField);
        System.out.println(subObject.baseField);
        System.out.println(((BaseClass)subObect).getBaseField());
        System.out.println(((BaseClass)subObect).baseField);
    }
}

Will print out:

base
sub
base
sub
sub
base

When you call a method, the JVM will start at the bottom of the inheritance hierarchy and call the appropriate method. When you reference a field instead, it uses the class of the pointer instead of walking up the class hierarchy to resolve the value. The behavior of the field reference matches what you're seeing, which is why I ask for clarification/verification.

Upvotes: 0

Ben Lings
Ben Lings

Reputation: 29443

Add @Override to the method in your subclass and recompile. This will help you find out if you're not actually overriding the method you think you are.

i.e.

public class Base {
    public String getApple() {return "base apple";}
}

public class Extended extends Base{
    @Override
    public String getApple() {return "extended apple";}
}

Upvotes: 1

Noah Campbell
Noah Campbell

Reputation: 1052

You should investigate what is constructing your instance that is returned from info.getForm(). You may want to make the Base abstract to prevent it from being instantiated and you'll quickly see where construction is happening.

Upvotes: 0

Daniel F. Thornton
Daniel F. Thornton

Reputation: 3685

Yuval is right that your cast in the if block has no effect. You might try combining your last statement with the if:

if (b instanceof Extended)
{
    // Prints "extended apple" if reached.
    System.out.println(((Extended)b).getApple()); 
}

Upvotes: 1

Laurence Gonsalves
Laurence Gonsalves

Reputation: 143314

First of all, that if block should never be necessary. It's basically a no-op.

Second, this isn't your real code, because it doesn't even compile. You're missing semicolons after the return statements.

I suspect that your problem is that your real code has a typo that's making the signatures of the two getApple methods different. This means that Extended has two methods: the one inherited from Base and the one with a different signature in itself. Since you're calling with the signature of the Base.getApple method, you're always getting that behavior. This is only a guess though, as your posted code does not exhibit the problem you describe.

Upvotes: 1

Brandon Yarbrough
Brandon Yarbrough

Reputation: 38399

As written, your code will not compile, which makes me think that your problem is elsewhere. Your return statements don't have semicolons at the end of them. Rather, they appear after the }. It's possible you had some other problem (maybe your subclass misspelled getApple()), but you're still using your old class files because your new stuff isn't compiling.

This code works:

class Base {
   public String getApple() { return "base apple"; }
}
class Extended extends Base {
  public String getApple() { return "extended apple"; }
}
public class Test {
  public static void main(String[] args) {
     Base b = new Extended();
     System.out.println(b.getApple());
  }
}

Console:

#javac Test.java
#java Test
extended apple

Upvotes: 4

Yuval Adam
Yuval Adam

Reputation: 165340

First:

if (b instanceof Extended){
    b = (Extended) b;
}

does absolutely nothing. You are basically saying b = b, which says nothing. You are not even changing the reference.

Second, getApple() will always be dynamically bound, and the "extended apple" should always be called - given that the subclass is truly extending the base class, and the method is truly overridden.

Basically what you need to do, in order to accomplish correct getApple() behavior:

  • remove the if clause. it does nothing.
  • make sure your class is indeed extending the base class
  • make sure the getApple() method is overriding the base class method. (use the @override annotation if you are not sure)

Upvotes: 6

AdamC
AdamC

Reputation: 16303

The only way to get that behavior is to return super.getApple() in your extended class, which is effectively the same as not overriding it in the first place. The only way this could help is if you pass in an argument to decide which to return. Not saying thats good design...

Forgot to mention that, as Yuval said, the cast does nothing to the object.

Upvotes: 0

Related Questions