2

I am practicing for an exam, and found a sample problem that gets me totally lost. For the following code, find what the output is:

class Moe {
    public void print(Moe p) {
        System.out.println("Moe 1\n");
    }
}
class Larry extends Moe {
    public void print(Moe p) {
        System.out.println("Larry 1\n");
    }
    public void print(Larry l) {
        System.out.println("Larry 2\n");
    }
}
class Curly extends Larry {
    public void print(Moe p) {
        System.out.println("Curly 1\n");
    }
    public void print(Larry l) {
        System.out.println("Curly 2\n");
    }
    public void print(Curly b) {
        System.out.println("Curly 3\n");
    }
}
public class Overloading_Final_Exam {
    public static void main (String [] args) {
        Larry stooge1 = new Curly();
        Moe stooge2 = new Larry();
        Moe stooge3 = new Curly();
        Curly stooge4 = new Curly();
        Larry stooge5 = new Larry();
        stooge1.print(new Moe()); 
        ((Curly)stooge1).print(new Larry()); 
        ((Larry)stooge2).print(new Moe()); 
        stooge2.print(new Curly()); 
        stooge3.print(new Curly()); 
        stooge3.print(new Moe()); 
        stooge3.print(new Larry()); 
        ((Curly)stooge3).print(new Larry()); 
        ((Curly)stooge3).print(new Curly()); 
        stooge4.print(new Curly()); 
        stooge4.print(new Moe()); 
        stooge4.print(new Larry()); 
        stooge5.print(new Curly()); 
        stooge5.print(new Larry()); 
        stooge5.print(new Moe()); 
    }
}

I had my ideas in mind, but then when I ran the java, I got something totally different:

Curly 1
Curly 2
Larry 1
Larry 1
Curly 1
Curly 1
Curly 1
Curly 2
Curly 3
Curly 3
Curly 1
Curly 2
Larry 2
Larry 2
Larry 1

The first few ones are OK, but then I really don't understand. Anyone has a good explanation for this problem?

Thanks

3 Answers 3

5

I would start by drawing a picture...

Moe - print(Moe)
 |
Larry - print(Moe), print(Larry)
 |
Curly - print(Moe), print(Larry), print(Curly)

Then I would keep track of the variables:

  • Larry - stooge1 -> Curly
  • Moe - stooge2 -> Larry
  • Moe - stooge3 -> Curly
  • Curly - stooge4 -> Curly
  • Larry - stooge5 -> Larry

  • stooge1.print(new Moe())

    • stooge1 -> Curly so calls Curly.print(Moe)
  • ((Curly)stooge1).print(new Larry());

    • stooge1 -> Curly so calls Curly.print(new Larry())
  • ((Larry)stooge2).print(new Moe());

    • stooge2 -> Larry so calls Larry.print(new Moe());
  • stooge2.print(new Curly());
    Ok, this is where it gets a bit trickier (sorry I stopped one before here)

    • stooge2 is declared to be a Moe. So when the compiler is looking at what to call it is going to call the print(Moe) method. Then at runtime it knows that stooge2 is a Larry so it calls the Larry.print(Moe) method.

etc...

Let me know if following that all the way through doesn't work out for you.

(updated to clarify the next one)

So the general rule is:

  • the compiler looks at the variable type to decide what method to call.
  • the runtime looks at the actual class that the variable is point at to decide where to get the method from.

So when you have:

Moe stooge2 = new Larry();
stooge2.print(new Moe());

the compiler says:

  • can Larry be assigned to stooge2? (yes as Larry is a subclass of Moe)
  • does Moe have a print(Moe) method? (yes)

the runtime says:

  • I am supposed to call the print(Moe) method on this here object... stooge2
  • stooge2 is point at a Larry.
  • I'll call the print(Moe) method in the Larry class.

Once you have worked all that out try getting rid of some of the methods and see how that changes things.

Sign up to request clarification or add additional context in comments.

5 Comments

the first 3 are straight-forward. If you could go on with the next 3 that would help. Thanks!
the above changes should help.
@TofuBeer - Not exactly correct. In a pure dynamic binding case stooge2.print(new Curly()) would print "Larry 2" not "Larry 1", since Curly extends Larry. (Actually stooge2.print(new Larry()) would have been a better example, since it would also print "Larry 1" instead of "Larry 2".
Which would make the error more obvious. The fact that overloaded methods are statically bound is why it is NOT called. Since in this case the method is dynamically bound, which only occurs with overridden methods.
Yes, stooge2.print(new Larry()) would be the same as stooge2.print(new Moe()) since Moe doesn't have a print(Larry) method. In Java there is no way, in the language, for stooge2.print(new Larry()) to call the Larry.print(Larry) method.
2

Actually, this problem is not as simple as it seems, since Java is both static and dynamically bound. You have to understand where each is applied before you will understand all the results you are getting from this exercise.

The General rule mentioned by TofuBeer is only correct in the dynamic binding case. In static binding, decisions are only made at compile time.

Your example mixes the dynamic binding (when methods are overridden) and static binding (when methods are overloaded).

Take a look at this question for more details.

Comments

0

A hint is to disregard the value on the left when looking at objects. Instead, look at the value of the right during the declaration, this is the actual value of the object.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.