Reputation: 331
I have the following illustrative code written in Java. It shows the overriding of the introduceYourself()
method for the different bikes.
public class Bicycle{
public void introduceYourself(){
System.out.println("Hello I am just a bicycle.");
}
}
public class MountainBike extends Bicycle{
public void introduceYourself(){
System.out.println("Hello I am a mountain bike and I love going outdoors.");
}
}
public class CityBike extends Bicycle{
public void introduceYourself(){
System.out.println("My name is city bike and I prefer calm trips.");
}
}
Just as I was expecting, the following code calls the introduceYourself()
method for each run-time object, although the variables were declared as the base Bicycle
class. This would be useful if I were to add Bicycle or Bicycle subtype objects to an array and call the method on a loop.
public class HelloWorld{
public static void main(String []args){
Bicycle b1 = new Bicycle();
Bicycle b2 = new MountainBike();
Bicycle b3 = new CityBike();
b1.introduceYourself(); // Output: Hello I am just a bicycle.
b2.introduceYourself(); // Output: Hello I am a mountain bike and I love going outdoors.
b3.introduceYourself(); // Output: My name is city bike and I prefer calm trips.
}
}
However, I am having trouble understanding the behaviour of this other code. I have the following classes which, again, show inheritance, but methods with different signatures (overloading):
public class A{
public int calc (double num){
return (int)(num + 1);
}
}
public class B extends A{
public int calc (long num){
return (int)(num + 2);
}
}
public class C extends B{
public int calc (int num){
return (num + 3);
}
}
public class D extends C{
public int calc (float num){
return (int)(num + 4);
}
}
And the following code in the main method:
public class HelloWorld{
public static void main(String []args){
int num1 = 10;
long num2 = 10;
A a1 = new D();
D d1 = new D();
System.out.println(a1.calc(num1)); // Output: 11
System.out.println(a1.calc(num2)); // Output: 11
System.out.println(d1.calc(num1)); // Output: 13
System.out.println(d1.calc(num2)); // Output: 12
}
}
Why does the object referenced by a1
(with declared type A
and run-time type D
) call the method declared in A
instead of the most-appropiate one (by signature) known by its runtime object of class D
? (Also, I suppose there is an automated casting, since the argument type is not the same.) Why does it seem to behave so differently from the Bicycle example? Thanks.
Upvotes: 0
Views: 611
Reputation: 82
The calc methods in B, C, D don't override the calc mehtod in A, so when you invoke calc via a1(It's a A), it actually call the method define in A(public int calc (double num)), so the result is 11.(That is to say, a1 is treated as a A, not a D. And note that there is only one method define in A)
But when you invoke calc via d1, which has defined 4 versions of calc, the result is depends on the type of your argument and the parameter.
Upvotes: 0
Reputation: 1017
Polymorphism only takes over if you're overriding. Here you're overloading different methods so when you declare:
A a1 = D();
Remember, the parent class knows nothing about the child class's method, but the child class knows about the parent class's method. So here you might substitute D for A, but you cannot call D's method. Sorry if my english sucks, but TLDR: A only knows 1 method calc(double num) and because double num can also accept int and long, that's why the function works. Otherwise it wouldn't work.
Lets say in the first example you have a method introduceYourSelf(String name) in class CityBike and you do something like this:
Bicycle bike = new CityBike();
bike.introduceYourSelf("I'm a city bike"); //error - Bicycle does not have method with argument string
Upvotes: 1
Reputation: 21004
Why does the object referenced by a1 (with declared type A and run-time type D) call the method declared in A instead of the most-appropiate one...
Actually, it's not the most appropriate one.
Consider Widening primitive conversions which will be used for chosing the most appropriate method.
The possible conversions are :
byte to short, int, long, float, or double
short to int, long, float, or double
char to int, long, float, or double
int to long, float, or double
long to float or double
float to double
You expect the method that takes a float as parameter to be chosen. However as you can see in the above list, double can never fit in another type than... double.
JLS 15.12.2.5 close the interrogation :
The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.
Hence since float can be passed to double and double can't be passed to float, the method from A is chosen as the most appropriate.
Why does it seem to behave so differently from the Bicycle example?
In the bicycle example, you are overriding methods while in the second example you are overloading. When overloading the most appropriate method (according to JLS 15.12.2.5) while when overriding you will call the "nearest" method of your runtime object.
Upvotes: 0