Java casting, overide and polymorphism - java

In the following example, I reckon it's something about run time polymorphism, but I can't figure out why y.m1(x) prints out A. My understanding is that y.m1() calls the m1()method in class B, because y contains an object of B. Since x is passed to it as a parameter, and it belongs to the class A which is wider than B, won't it lead to a run-time error? Plus how come z.m1(y) prints out A too?
Many thanks in advance!
class A {
public void m1(A a) {
System.out.println("A");
}
}
class B extends A {
public void m1(B b) {
System.out.println("B");
}
}
class D2 {
public static void main(String[] args) {
A x = new A();
A y = new B();
B z = new B();
}
}

B's m1 does not override A's m1 method, as it does not take the same parameter. So B class consist of two overloaded m1 methods, one taking an A object, the other taking a B object.
Only static polymorphism can be used here, that's why you can see this behavior.

The dynamic type of an object (the type used in the new) is it's actual runtime type: it defines the actual methods that are present for an object.
The static type of an object reference (a variable) is a compile-time type: it defines, or rather declares, which methods can be called on the object the variable references.
Because the parameter type of both the dynamic type and the static type are different, we dynamic type doesn't override the method, but overloads it.
If the parameter types would have been the same, the output would be B...

Related

How to do Java polymorphism

Edit: should be a2 = new B()
I don't understand why the result for a2.foo(b) is 3 in the following practice question.
I thought with polymorphism, the dynamic types method would run with the method signature that takes the argument that corresponds with the static type.
public class A {
public int foo(Object o) {
System.out.println(1);
return 1;
}
public int foo(A a) {
System.out.println(2);
return 2;
}
}
public class B extends A {
public int foo(A a) {
System.out.println(3);
return 3;
}
public int foo(B b) {
System.out.println(4);
return 4;
}
public static void main(String[] args) {
A a2 = new B();
B b = new B();
a2.foo(b);
}
}
The answer my school has given is a2.foo(b) returns 3, however I thought it would return 4.
Thanks in advance!
There are two things going on here:
Overloading
Overriding
Overloading is about having two different methods in the same class with the same name but different argument types (so they are different). Overriding and polymorphism is about having the same single method in two different classes.
Classes A and B both overload the foo method: they have two methods with the same name. In A one method takes Object as a parameter and one takes A as a parameter. In B one takes A as a parameter and one takes B. Of these four methods, two are the same (foo(A)).
The foo(A) method in B overrides the foo(A) method in A. The foo(B) method however is a different method.
So when you call a2.foo(b) you are calling the foo(A) method. It must be, as a2 is declared as A and A doesn't have a A.foo(B). Since a2 is an actually an object of type B, you are calling B.foo(A) as it overrides A.foo(A).
EDIT: As the question was changed, the answer is now 3 as A.foo(A) is called but overridden.
If a2 was a B then the overridden method would be used, never an overloaded method.
But a2 is an A and which class only has one method foo(A) which can be called, so it prints 2
In short, only the type of this on the left hand side of . will change the choice of method called.
a2 is obviously A, therefore A#foo is executed. It is possible (compiles and executes) since B is instance of A.
Since A#foo is executed, answer is 2 (not 3 and not 4).

Java inheritance and method overloading

I've tried to execute the following code:
abstract 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 fun() {
return ((A) this).met((A) this);
}
}
class Test {
public static void main(String[] args) {
C x = new C();
System.out.println(x.fun());
}
}
And the output is "3".
Can someone explain in more detail the theoretical concept behind this result.
I know that class A is abstract and that's why it cannot be instantiated but I'd like to understand the whole mechanism of this result.
The overloaded method is selected at compile time. Since your code calls met((A) this), the method signature with the argument of type A is chosen.
Now, at run time, the JVM has to decide which met(A a) method to execute. This is determined by the runtime type of the object for which the method is called. Since your object is of type C which extends B, met(A a) of B (which overrides met(A a) of A) is executed.
Method signatures are determined at compile time.
.met(A)
must be called as the signature doesn't change based on the actual type of the object, only the type is appears to be.
However, polymorphism does apply to determine which implementation of this signature is called.
The object this is a C which extends B and so the implementation in B is the one called.
This is why B.met(A) is called.
B is the only class implementing A so A implementations will never be executed as B as overrided them.
When you cast your C object as A, it's still a C object so calling met on this object will execute the method of B. This call is resolved at runtime using the real type of the object.
Concerning the parameter, you casted it as a A so the java compiler made it point to the right method : B.met(A)
return ((A) this).met((A) this);
When you write this it's always points to current instance which is C which extends B, and you didn't over-ridden the method hence it's pointing to the method of super class (B).
And coming to the part (A) this, it still points to this only, not the A. The underlying implementation of methods still remains same. You are just changing type.
((A) this).met((A) this) interpreted as
- instanceOfC.met(typeOfA)
so two questions arise, why is
class selected as B not A - subclass over super class
within class B met is selected as met(A) not met(C) or met(B) - type over instance
A. Overriding - subclass over super class
if same method signature in the object's sub-class and super-class,
then it was selected it from sub-class.
so ((A) this).met resolver to instanceOfC.met
B. Overloading - type over instance
if duplicate method name found in the class
then selected was one with same parameter as the argument passed,
hence met ((A) instanceOfC) interpreted as met(typeOfArgument)
so
this.met((A) null) will also invoke B.met(A)
this.met(this) will invoke B.met(C)
if we remove B.met(C), this.met(this) will invoke A.met(C), i.e. overriding doesnt happen.
and then removing A.met(C), it will invoke B.met(B), - overloading by closest typecast-able parameter.

Why is the super class method called?

class One {
public void doThing(One o) {System.out.println("One");}
}
class Two extends One{
public void doThing(Two t) {System.out.println("Two");}
}
public class Ugly {
public static void main(String[] args) {
Two t = new Two();
One o = t;
o.doThing(new Two());
}
}
Result : One
class One {
public void doThing(One o) {System.out.println("One");}
}
class Two extends One{
public void doThing(Two t) {System.out.println("Two");}
}
public class Ugly {
public static void main(String[] args) {
Two t = new Two();
One o = t;
t.doThing(new Two());
}
}
Result : Two
I know that at runtime, even though the object reference is of the super class type, the actual object type will be known and the actual object's method will be called. But if that is the case, then on runtime the doThing(Two t) method should be called but instead the super class method doThing(One o) is called. I would be glad if somebody explained it
In the second piece of code it prints "Two".
Question : when calling from the super class reference it is calling the doThing(One o)
when calling from the sub class reference it is calling the doThing(Two o)
NOTE: I know that i am over loading and not over riding. i have edited my question for better clarity.
The method doThing() have different method signature in One and Two.
One.doThing(One one)
Two.doThing(Two two)
Since, the signature isn't matched, Two.doThing(Two) doesn't Override One.doThing(One) and since o is of type One, One.doThing() is called.
Also to be noted that One.doThing(One) can take instance of Two as an argument for One.doThing(One) as Two extends One.
Basically, "#nachokk - You are Overloading, not Overriding"
In first scenario, when you did
Two t = new Two();
One o = t;
o.doThing(new Two());
So, o is an instance of One and Two.doThing(Two) isn't available to o thus calls One.doThing(One)
In second scenario,
Two t = new Two();
One o = t;
t.doThing(new Two());
t is an instance of Two and thus Two.doThing(Two) is called.
The excelent book SCJP for Java 6 states:
If a method is overridden but you use a polymorphic (supertype)
reference to refer to the subtype object with the overriding method,
the compiler assumes you’re calling the supertype version of the
method.
So basically with using supertype for reference you're telling compiler to use supertype method.
You are just overloading,as you said
Two t = new Two();
One o = t;
o.doThing(new Two());
Even though the actual object at runtime is a Two object and not a One object, the
choice of which overloaded method to call (in other words, the signature of the
method) is NOT dynamically decided at runtime. Just remember, the reference
type (not the object type) determines which overloaded method is invoked!
When you call doThing() method with Two object argument,you will invoke One super class doThing() method.The doThing() method needs a One object, and Two IS-A One.
So, in this case, the compiler widens the Two reference to a One object, and
the invocation succeeds. The key point here is that reference widening depends on
inheritance, in other words the IS-A test.
This is something trick question
Your statment
One o = t;
I think , you are assuming that class One 'o' is equal to Class Two 't', which is not actually equal to class Two 't'
as Class Two 't' is inherited from Class One, so it will assign the base class One in your case,
So variable 't' is reference of the class One and hence will call the method of class One.
More over you create one more class named as ClassC class and try to set your statement
ClassC c= new ClassC () and then
One o = c;
You will get an error... hope the answer your question.
At the compile time the compiler searches the class One for the method doThing(Two t) but since there isn't a method with that signature it starts widening its search and finds doThing(One o). Then it holds the binary file with the descriptor one parameter whose type is One : void. At runtime since the object invoking the method is of type Two, in class Two it looks for the method that matches the descriptor and doesn't search for the method doThing that accepts an object of Two as it considers the descriptor in the binary file it links the call to the method doThing(One o).
the java specs was of great help explaining this. here is the link

Java calling subclass method when trying to use parent class method

If I have two classes, A and B,
public class A {
public int test() {
return 1;
}
}
public class B extends A{
public int test() {
return 2;
}
}
If I do: A a1 = new B(), then a1.test() returns 2 instead of 1 as desired.
Is this just a quirk of Java, or is there some reason for this behavior?
This is called polymorphism. At runtime the correct method will be called according to the "real" type of a1, which is B in this case.
As wikipedia puts it nicely:
The primary usage of polymorphism in industry (object-oriented
programming theory) is the ability of objects belonging to different
types to respond to method, field, or property calls of the same name,
each one according to an appropriate type-specific behavior. The
programmer (and the program) does not have to know the exact type of
the object in advance, and so the exact behavior is determined at
run-time (this is called late binding or dynamic binding).
No, that is correct (it is due to polymorphism). All method calls operate on object, not reference type.
Here your object is of type B, so test method of class B will be called.
This is polymorphism and more specifically in Java overriding. If you want to invoke Class A's test method from Class B then you need to use super to invoke the super classes method. e.g:
public class B extends A{
public int test() {
return super.test();
}
This is intended behavior. The method test() in class B is overriding the method test() of class A.
For
A a1 = new B();
a1 is pointing towards the object of B which is the real type at run-time. Hence value is printed from Object B.
A obj = new A();
obj.test()
will return 1
A obj = new B();
obj.test()
will return 2
B obj = new B();
obj.test()
will return 2
As stated in other answers this is how polymorphism works.
This post may make things a bit clearer
Java uses dynamic binding (or late binding), so the method of B is called, not A. This is the opposite of static binding. There is a nice example here.
You declare your object as A but your instance is B. So the method which will be called is from class B. B extends A(we can say that A is parent for B) if you will comment method test in B and then recall this method, in this case the method invoked will be test from A class and will return 1.

Why does sysout(upper class) invoke toString of lower class after assigning lower class to upper class?

I have two classes A and B while B is a subtype of A:
public class A {
private String stringVar;
public A() {
stringVar = "";
}
public String getStringVar() {
return stringVar;
}
public void setStringVar(String str) {
this.stringVar = str;
}
#Override
public String toString() {
return getStringVar();
}
}
Class B:
public class B extends A {
private int intVar;
public B() {
intVar = 0;
}
public int getIntVar() {
return intVar;
}
public void setIntVar(int intVar) {
this.intVar = intVar;
}
#Override
public String toString() {
return super.toString() + " " + getIntVar();
}
}
As you can see in the following main method I assign the b to a. Now "a" can't invoke b's methods which is clear, because I'm using an instance of type A now. But it behaves like a B when toString is invoked. Curious, I would have expected toString of a. Why is this so?
public class Main {
public static void main(String[] args) {
A a = new A();
B b = new B();
b.setIntVar(200);
b.setStringVar("foo");
a = b;
System.out.println(a);
}
}
Because a points to the implementation of B.
And is declared as A.
So behavior of B. And methods visible of A.
To use B methods do like this
((B) a).getIntVar();
Think of it like this
Object o = new FancyObject();
When compiling this only Objects methods will be accepted even though it's a FancyObjcet with lots of methods.
To use the methods of FancyObject on o do like this.
Object o = new FancyObject();
(FancyObject o).fancyMethod();
Quote "because I'm using an instance of type A now" you are still using an instance of type B. You can see it like you have upcasted b but it's the same instance.
Picture cross linked from another site with credits in the picture, if this is against the rules then somebody is free to edit this part of my answer.
This is nature of inheritance / polymorphism and overriding methods.
Overrided methods will be determined in runtime based on objects real type and not based on reference type.
Therefore a.toString() is actually b.toString() because it is determined in runtime.
http://download.oracle.com/javase/tutorial/java/IandI/override.html
The concept you need to understand is the difference between References and Objects.
a is a reference (a local variable in this case) that points first to an Object of type A and then to an Object of type B.
The compiler knows that it must be of type A (or a subtype thereof), so it can safely call all methods A defines, but they will be called on the actual Object, not on the original Type of a.
This is polymorphism: The object that a holds has static type A, but it is still an Object of dynamic type B. Dynamic dispatch therefore chooses the overridden toString() defined in B.
That's exactly how Java's runtime polymorphism works. All that matters is the actual type at runtime. What you have done is take a reference to an A and point it at an instance of B. You have changed the type of the thing that a points to.
Try
a = (A)b;
No, B Overrides the toString method of A, so if an object is an instance of B, when you call its toString method, you get whatever method that instance has. In general, if you have an object and call its methods, the method called is the one that is in the instance, not in the variable type. The only exception is static methods.
In C++, this is not the case. The method called is the one of the variable type, if one exists, unless you explicitly select the above described behavior by making a method virtual.
That is called runtime polymorphism in OOP.

Categories

Resources