Java snippet output not understood, probably related to polymorphism - java

I was wondering why this bit of Java yields 2, and not 3 :
public class Test {
private static class A {
int f(A a) {
return 1;
}
}
private static class B extends A {
int f(A a) {
return 2;
}
int f(B b) {
return 3;
}
}
public static void main(String[] astrArgs) {
A ab = new B();
B b = new B();
System.out.println( ab.f(b) );
}
}
I came across this in a test question, and couldn't get the logic behind it.

The compile-time type of ab is just A. Therefore, when the compiler sees this expression:
ab.f(b)
... it only considers method signatures declared on A and its superclasses (just Object in this case).
So, the compiler makes the decision to call the method with the signature f(A a).
Now at execution time, the VM chooses which implementation of that signature to execute based on the execution-time type of the target of the method call, which is B.
B overrides f(A a), so that overriding implementation is called - and returns 2.
Basically, overloading is determined at compile-time to work out what method signature to call based on the compile-time types of both the target of the call and the arguments, and overriding is determined at execution-time to work out the exact implementation to execute based on the execution-time type of the target object.

In this case, ab is of type A, but instantiated as B. A only knows method
int f(A a) {
return 1;
}
b is of type A, so it is valid. B overrides int f(A a), so this method is used.
int f(A a) {
return 2;
}
Hope that helps.

Related

Java polymorphism: Why is this method called last?

i was trying to understand polymorphism in Java better with the following example:
public class A {
1 int method(A a) { return 1; }
2 static int method(B b) { return 2 + b.method((A)b); }
}
public class B extends A {
3 final int method(A a) { return 4 + super.method(a); }
4 int method(C c) { return 8 + this.method((B)c); }
}
public class C extends B {
5 int method(C c) { return 16 + method((A)c); }
}
And, the following declaration, initialization, methodcall:
B b = new B();
b.method(b);
I can not wrap my head around, why the "int method(A a) { return 1; }", is the last one to be called.
My train of thought so far:
We figure out the static and dynamic Type and of b (B and B)
We look in class B, if we find a method called method, which accepts parameter with static type B.
We find two candidates: 3, 2.
We call 2, because it requires no implicit casting to the static Type B in the parameter and the static and dynamic types of B are the same.
Now figure out the stat/dyn.types for b.method((A) b):
b is (B/B), and b in the parameter is (A/B) after the cast. Now, we look in class B for a Method called method, which accepts an A-type parameter, we find one,1, but now, because we have a different dynamic type (B), we also need so search B for a possible candidate, we find 3, we use it, since it overrides 1.
After that, we discern the types again, because of "super" the static type is the one from the parentclass (A), and the dynamic one: B (the dynamic type of the object which caused the super-call), and A and A for its parameter.
So, now we seek in A for a method which accepts an A, we find 1, but the dynamic class is different, so we need to also check for candidates, in class B, which might overwrite the method found in A (1), and use it, if that is the case, which would lead us to calling method 3, again.
But obviously that is not what Java returns, and i do not know where the error to this approach is. In other polymorphism exercises, i came to the correct solution.

Java - Problems with understanding inheritance

I am facing some problems about inheritance in Java.
I can't understand why the following two programs have those outputs!
Could anyone help me? :)
1)
public class A {
int foo() {
return 1;
}
}
public class B extends A {
int foo() {
return 2;
}
}
public class C extends B {
int bar(A a) {
return a.foo();
}
}
C x = new C();
System.out.println(x.bar(x));
// OUTPUT:2
2)
public class A {
int e=1;
}
public class B extends A {
int e=2;
}
public class C extends B {
int bar(A a){
return a.e;
}
}
C x= new C();
System.out.println(x.bar(x));
// OUTPUT:1
In both cases, you're passing in an object of type C into the print function. The bar function asks for an object of type A, but it's still acceptable for you to pass in an object of type C since it is a subclass of A. So first of all, it's important to keep in mind that a.foo() and a.e are being called on a C object.
So what is happening in both cases is that it's searching for the lowest attribute or method in the list. Here is a very simplified version of what Java is doing in part 1:
Hey, you've passed in an object of type C to the bar method! Now let's call its foo method.
Whoops! C doesn't have a foo method! Let's take the next step up to the B class to see if it has a foo method.
Yay! B has a foo method, so let's call it. No need to work our way up to the A class because we've already found what we need in B.
It's all about understanding that the parameter was downcast from A to C. The exact same sort of logic is used in part 2. It notices that an object of type C was passed in, so it gets the e attribute from object B since its the lowest class in the hierarchy that contains that attribute.
Hopefully that answers your question!

Overloading method on extended class

Simple question, strange result. I have two classes A and B:
public class A
{
protected int num;
public A(int n)
{
num = n;
}
public boolean f(A a)
{
return num == a.num * 2;
}
}
public class B extends A
{
public B(int n)
{
super(n);
}
public boolean f(B b)
{
return num == b.num;
}
}
Why does y1.f(y2) call the f() method in A instead of in B?
A y1 = new B(10);
B y2 = new B(10);
System.out.println(y1.f(y2));
Is it not supposed to call f() in B as B is more specific than A?
Why does y1.f(y2) calls the f() method in A instead of in B?
Because the compile-time type of y1 is A.
Overloading is performed at compile-time... the execution-time type of the object you call the method on is only relevant for overriding.
So the compiler is choosing the method f(A) as that's the only f method it's aware it can call on y1 (and it's checked that it's applicable given the argument list). That method isn't overridden in B, therefore at execution time, the implmenetation in A is called.
As a starker example, consider this code:
Object x = "foo";
int length = x.length();
This won't even compile, because Object doesn't contain a length() method. String does, but the compiler doesn't consider that, because the compile-time type of x is Object, not String - even though we can tell that at execution time, the value of x will be a reference to a String object.

What does it happen when a superclass reference which is assigned to an object of subclass invokes an overriding method?

Here is the code:
class Override {
public static void main(String[] args) {
A a = new A(1, 2);
A a1 = new B(1, 2, 3);
B b = new B(4, 5, 6);
a.show();
a1.show();
b.show();
}
}
class A {
int a;
int b;
A(int a, int b) {
this.a = a;
this.b = b;
}
void show() {
System.out.println(a + " " + b);
}
}
class B extends A {
int c;
B(int a, int b, int c) {
super(a, b);
this.c = c;
}
void show() {
System.out.println(c);
}
}
Restult:
1 2
3
6
A reference variable of a superclass can be assigned to an object of any subclass derived from that superclass.
The type of the reference variable determines what member can be access.
Based on the fact above, a1 cannot access to c(member of B), since a1 doesn't know the existence of any member in B. My question is when a1 calls on show(), why is the show() in B being invoked instead of that of A?
Thank all of you for your answers.
Here is something I think very interesting:
Dynamic method dispatch is a mechanism by which a call to an overridden method is resolved at run time.
When an overridden method is called through a superclass reference, java determines which version of that method to execute based on the type of the object being referred to at the time the call occurs.
Because B has overridden the method show() the show() in B is invoked. Consider an abstract method, if B couldn't replace the abstract method it could never be implemented (likewise with interfaces).
abstract void show();
Finally, if the method shouldn't be overridable make it private. The default level of access is inherited.
The function from B will be called.
this mechanism is called "Virtual Functions".
if a subclass overrides a function in the base class , the program will search the right function on run time and invokes it for the right type (B and not A).
in Java , all functions are virtual.
but your question is right , though , in C++ and C# , the functions are not virtual by default, if they are not declared as virtual explicitly , the function from A will be called (in equivalent C++/C# code);
Because your class B overrides the show() method. The superclass method is only used if the inheritor does not override it.

cast on object of type superclass returns object of type subclass in java

I have implemented the following code in order to understand the difference between static and dynamic binding:
class A {
int met(A a) {
return 0;
}
int met(B b) {
return 1;
}
int met(C c) {
return 2;
}
}
class B extends A {
int met(A a) {
return 3;
}
int met(B b) {
return 4;
}
int met(C c) {
return 5;
}
}
class C extends B {
int f() {
return ((A)this).met((A)this);
}
}
public class Test {
public static void main(String[] args) {
C x = new C();
System.out.println(x.f());
}
}
The result I get is 3, but I don't understand why, since the first cast is made to A.
So, let's look at the call:
((A)this).met((A)this);
That's equivalent to:
A target = this;
A argument = this;
target.met(argument);
So, for the last line, the compiler looks up the signature based on the compile-time types involved - it will look in A (and superclasses) for a method called met which has a parameter that is compatible with A (the compile-time type of the argument). Overload resolution finds that the answer is:
int met(A a)
That's determined the signature at compile-time. However, the implementation of that method is determined at execution time, based on the execution-time target of the method call. That type is C here - because this is a reference to an instance of C. (The f method is called on an instance of C.)
Now C doesn't override int met(A a), but B (its superclass) does - so that's the implementation that's used. It doesn't matter that B also overrides met(B b) and met(C c) because the compiler has already determined that it's the met(A a) method which is being called.
This is two questions for the price of one. (1) Why do we get the implementation from class B, and (2) why do we get the version of the method with the parameter of type A.
For question (1), the thing to remember is that the class of an object doesn't change when you cast it, or assign it to a variable whose type is something different. So in your example, the class of this is always C, because that's what you created. Class C inherits its version of met(A a) from class B because it doesn't have its own version, and because class B has overridden the version in class A. This is what polymorphism is all about - the version of the method depends on the class of the object that you call it on, not on the type of the expression that you use to call it.
For question (2), it's a wee quirk of Java that method signatures are evaluated at compile time. So the compiler sees that you're passing an expression of type A into your method, so it chooses the signature met(A a). Because this decision is made at compile time, the actual class of the argument doesn't make any difference - the compiler has already chosen the method, based on the type of the expression. In other words, Java doesn't give you polymorphism of method parameters.

Categories