views:

239

answers:

8

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?

A: 

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.

AdamC
+6  A: 

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)
Yuval A
I assume he is using it to determine absolutely that his b really is an Extended.
CaptainAwesomePants
But it still changes nothing... The if clause has no effect whatsoever.
Yuval A
The if clause does nothing, in java "casts" just make sure that the cast is allowed, they don't actually do a "cast", unlike C for example.
Michael Wiles
+4  A: 

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
CaptainAwesomePants
As a side note, this works because all methods in Java are virtual.
R. Bemrose
From a C++ perspective, that is correct. More precisely, all method calls in Java are dynamically bound at runtime.
Yuval A
+1  A: 

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.

Laurence Gonsalves
+1  A: 

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()); 
}
pianoman
totally unnecessary. "extended apple" will be printed even if you do not cast to (Extended).
Yuval A
I guess the behavior he reported in his code comment is the result of something else then?
pianoman
A: 

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.

Noah Campbell
+1  A: 

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";}
}
Ben Lings
A: 

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.

Peter Nix