Welcome to the CSC Q&A, on our server named in honor of Ada Lovelace. Write great code! Get help and give help!
It is our choices... that show what we truly are, far more than our abilities.

Categories

+36 votes

I am still not getting how the parameters are determined between the declared type and actual type and what method it will first look at and then choose. Can anyone explain how it works using the Automobile example?

asked in CSC285_Fall2018 by (1 point)
+3

Cross-reference -- did you also read the answer to this similar question.

1 Answer

+13 votes

Overloading/overriding along with dynamic method invocation... can feel complex/confusing, although it's fairly logical once you get the hang of what's going on. Let me try to help:

It's very important to realize that this is a two-phase process.

Phase 1: Compile-time. This is where Java source code (.java text files) gets turned into JVM byte code (.class binary files).

At this point, the compiler can't generally tell the "actual" type of any variable. The variables don't have values yet -- they're just names/symbols, and won't get values until the program is run. It only knows the declared types for sure, so that's what it uses. Why? Suppose you have a method: public void service(Automobile x) { ... x.drive(15); ... }

The compiler has no way of knowing whether x will actually be an instance of type Automobile, or whether it will actually be an instance of some subclass of Automobile (like SUV or MonsterTruck). That's the way polymorphism works.

During Phase 1, the Java compiler only looks at the declared type of the object that the method is being invoked on, and the declared types of any parameters. If there are multiple (overloaded) methods with that same name, it finds the method that is the closest match that can accept the declared type of the parameters. Let's say it picks Automobile.drive(int distance). (A method's signature is defined by its name and it's parameter types).

Phase 2: runtime. At runtime, all variables DO have actual values. So at this point Java knows that the variable x being passed into the service(...) method is actually a Minivan (for example).

The Java designers wanted to allow the Minivan class to provide more specific functionality, so IF the Minivan class has overridden the Automobile.drive(int ...) method with a Minivan.drive(int ...) method, that overriding method will be invoked instead.

However, Java does NOT look at (re-examine) the actual types of all of the parameters when deciding which method to call. That would be too inefficient, and time is very precious during runtime, since extra time deciding which method to call will delay actually calling the method. So Java only does a quick check to decide if the method that the compiler previously chose has an exact matching method (same name AND declared parameter types) that overrode it in the actual object's class (or in any class between the two, if the actual type is a grandchild or other descendent from the superclass.)

If an exact-parameter-matching overriding method isn't found, then Java simply runs the method that the compiler picked out.

answered by (3.5k points)
+9

For example, recall that:

Object autoObject = new Automobile();
Automobile auto = new Automobile();

Look at the UML diagram in Figure 2.13 and consider autoObject.equals(auto)

Phase 1: The declared type of autoObject is Object, so at compile time, the Java compiler can only look in the Object class to see what equals method might work. There's only one equals method there, so it must choose Object.equals(Object), even though the parameter auto is declared as Automobile.

Phase 2: At runtime, Java looks at autoObject and knows that it is really an instance of Automobile. It checks whether Automobile has overridden the method that the compiler chose (which was equals(Object)) -- and indeed it has overridden that exact method. Thus, Java will run the overridden version, Automobile.equals(Object), but it DOES NOT consider running the Automobile.equals(Automobile), even though a programmer might feel that would be the more appropriate choice, given that the actual (and declared) type of the auto argument was an Automobile object.

...