class A{
void m1(A a) {System.out.print("A");}
}
class B extends A{
void m1(B b) {System.out.print("B");}
}
class C extends B{
void m1(C c) {System.out.print("C");}
}
public class d {
public static void main(String[] args) {
A c1 = new C(); C c2 = new C();c1.m1(c2);
}}
Output of this code is 'A'.
But if I modify class A as:
class A{
void m1(C a) {System.out.print("A");}
}
then the output is 'C'. Could somebody please explain how is this code working?
(You've made this more confusing than it needs to be by using the same inheritance hierarchy for both the parameter types and the implementation. Separating those would probably help to simplify it in your mind.)
The type of c1 is A. Therefore when working out which method signature it's going to call, the compiler can only look at methods declared in A.
So in the first case, the compiler is going to call m1(A); in the second case, the compiler is going to call m1(C).
Now in the first case, the m1(A) method is never overridden, so actually the execution-time type of c1 is irrelevant.
In the second case, m1(C) is overridden by C, so the implementation in C is called because the execution-time type of c1 is C.
So remember:
Overload resolution (which method signature is called) is determined at compile-time, based on the compile-time types of both the method target and the argument expressions
The implementation of that method signature (overriding) is based on the actual type of the target object at execution time.
Related
class A {
public int a = 100;
}
class B extends A {
public int a = 80;
}
class C extends B {
public int a = 10;
public void show() {
int a = 0;
System.out.println(a);
System.out.println(super.a);
System.out.println(((A) this).a);
}
}
What does ((A) this).a in the line System.out.println(((A) this).a); do?
Is it upcasting/downcasting thisor is something else happening here?
I also tried System.out.println(this); and System.out.println((A)this); and they both have the same output. What exactly is happening here?
In the java programming language, we have classes. When we write java code, we create instances of those classes, for example:
Object o = new Object();
Object is a class. Writing new Object() creates an instance of that class. The above code declares a variable o and assigns it [a reference to] an instance of class Object.
In the terminology of the java programming language, we say that variable o has type Object.
In the code in your question, a variable that is assigned an instance of class C, really has three types.
It has type C.
It has type B since B is the superclass of C.
It has type A because it indirectly extends class A also.
In the context of the code in your question, this is a special variable whose type is C. Writing (A) this is telling java to relate to the variable this as if its type is A.
Class A cannot access its subclasses. Hence it is only aware of its class member a. Hence when you write this line of code...
((A) this).a
You are accessing the member of class A only.
System.out.println(a);a is the one from the show method of your C class → a = 0
System.out.println(super.a);a is the one from the super-class of C, which is B → a = 80
System.out.println(((A) this).a);First, you cast your C instance (this) into A, then you call a which is a member of the A class → a = 100
There is also something to consider : method will always take the more specialized one (except if super is used), where field will be taken directly from the type referenced (even if there is an extending class).
For example, if I add getA() in each classes :
class A {
public int a = 100;
public int getA(){
return a;
}
}
class B extends A {
public int a = 80;
public int getA(){
return a;
}
}
class C extends B {
public int a = 10;
public int getA(){
return a;
}
public void show() {
int a = 0;
System.out.println(a);
System.out.println(super.a);
System.out.println(((A) this).a);
System.out.println(getA());
System.out.println(super.getA());
System.out.println(((A) this).getA());
}
}
class Scratch {
public static void main(String[] args) {
new C().show();
}
}
I get the following output :
0
80
100
10
80
10
Which means that in the case of the method, except in the case of super.getA() which explicitly goes to the superclass, casting your C into a A doesn't change much for methods, as it impacts the field.
If you write something like obj.a, obj.getA() or someMethod(obj), Java somehow has to find the actual field or method to be used, based on the type or class of obj. There are two distinct dispatch mechanisms involved (plus the special construct super).
Dynamic dispatch (polymorphism, overriding): This is used when calling an instance method on the object, as in obj.getA(). Then the runtime class of the obj is examined, and if this class contains a getA() method, this is used. Otherwise, the direct parent class is examined for a getA() method, and so on up to the Object class.
Static dispatch: In cases like obj.a or someMethod(obj), the runtime class of obj doesn't matter. Involved is only the compiler, and from his knowledge of obj's type, he decides which field or method to use.
super dispatch: If you write super.getA() or super.a, your getA() method or a field is ignored, and instead the next-higher class in the hierarchy is used that contains such a method or field.
In your case you have 3 fields plus one local variable, all with the same name a. (By the way, it's a very bad idea to have such name conflicts in professional code.) We are inside a method show() declared in the C class. Let's have a look at some different expressions and what they mean here:
a references the local variable a. There's no dispatch needed, it's just that local definitions take precedence over fields.
this.a is a static-dispatch expression, so it's important what the compiler thinks about the type of this. And that's always the class where this code has been written. In your case, it's class C, so the field a from class C is used, the one being 10.
super.a is a super-dispatch expression, meaning that the a field from this class C is ignored and the next higher one taken (the one from B, in our case).
((A) this).a is static dispatch, but the (A) casting has a significant effect. The expression before the dot originally comes from this, being of type C, but the (A) cast tells the compiler to believe it were of type A. This is okay, as every C also is an A, by inheritance. But now, static dispatch sees something of type A in front of the dot, and dispatches to the a field from the A class, and no longer from C.
getA(), this.getA() and ((A) this).getA() are all dynamic-dispatch examples, all giving the same result. The method called will be the one based on the runtime class of this object. This will typically be one defined in the C class. But if show() was called on an object of a subclass of C, e.g. D, and D had its own getA() method, that one would be used.
super.getA() is a case of super-dispatch, it will call the getA() method next higher up in the class hierarchy from the current class, e.g. B.
System.out.println(this);
And
System.out.println((A)this)
These two prints the object reference to class C with toString() method.
System.out.println(((A)this).a);
This is upcasting, child object to parent object.
In the following program, I have one single method in class A overloaded 3 times and then in subclass B, all 3 overloaded methods are overridden.
obj3 is an object with reference type A(superclass) and object type B(subclass) and it calls the method from B on execution, which is expected behavior.
Since overloading and overriding both exist in this code, does that mean that it performed static binding at compile time (to the matching method in class A) and then dynamic binding at run time (to method in class B). Can they both occur together?
My assumption is that this is a classic case of dynamic binding as I believed "binding" is meant to be a permanent action, but a peer suggests that it is both together(static first, then dynamic).
class A{
public void method(Integer n){
System.out.println("Integer: "+n);
}
public void method(String s){
System.out.println("String: "+s);
}
public void method(String s, Integer n){
System.out.println("String: "+s+" Integer: "+n);
}
}
class B extends A{
public void method(Integer n){
System.out.println("Integer(from B): "+n);
}
public void method(String s){
System.out.println("String(from B): "+s);
}
public void method(String s, Integer n){
System.out.println("String(from B): "+s+" Integer(from B): "+n);
}
}
public class Test{
public static void main(String[] args){
A obj1 = new A();
B obj2 = new B();
A obj3 = new B();
System.out.println("Integer form of method");
// Integer form of method
System.out.println("Ref A Obj A");
// Ref A Obj A
obj1.method(1);
// Integer: 1
System.out.println("Ref B Obj B");
// Ref B Obj B
obj2.method(2);
// Integer(from B): 2
System.out.println("Ref A Obj B");
// Ref A Obj B
obj3.method(3);
// Integer(from B): 3
}
}
Since overloading and overriding both exist in this code, does that mean that it performed static binding at compile time (to the matching method in class A) and then dynamic binding at run time (to method in class B)
Right. The compiler chose the matching signature, and this is static, based on the type of the variable (A in this case).
At runtime, Java finds the implementation of the signature selected by the compiler. This is dynamic, based on the runtime class of obj3 (B, in this case).
You right. Compiler is statically choose between overloads in class A and put that information into .class file in form of method FQN.
Then runtime dynamically choose between implementation of that method.
One more attempt to make it clear:
Overloading
Overloading means that a single class has multiple methods with different parameter types (aka. signatures), and you just happened to give them the same name. Your program will work the very same if you change to individual names for the methods, e.g. methodI(Integer n), methodS(String s), and methodSI(String s, Integer n).
Or, you can imagine the compiler to internally always append such a types list to the method name.
Overloading is resolved by the compiler, based on the compile-time types of the parameter expressions.
E.g. if you write
Object par = "Test";
a.method(par);
you get a compiler error. Even though we all see it's a String that you are passing into the method, the compiler only sees an Object, and finds no matching method. Only if you were to introduce an additional method(Object o), the compiler would choose that one. And runtime would call that method and not the String version!
Overriding
Overriding means that at runtime the JVM calls the method implementation depending on the runtime class of the "object before the dot".
And in this case, "method" is to be read as the overloaded method version that the compiler found to match the parameter list. So, runtime already knows whether methodI(), methodS(), or methodSI() is meant, and only decides from which class to take the implementation.
Personal opinion
Allowing multiple methods to share the same name, but differ in parameter lists (aka overloading), produces too much confusion for its benefit.
Let's say I have the following interface and classes defined:
public interface I { void a(); }
public class A implements I {
public void a() { System.out.println("A"); }
}
public class B implements I {
public void a() { System.out.println("B"); }
public void b() { System.out.println("C"); }
}
And then I run the following code:
public class Main {
public static void main(String[] args) {
A a = new A();
B b = new B();
I i;
i = a;
i.a(); // prints "A"
i = b;
i.a(); // prints "B"
i.b(); // 1st problem: i can't seem to find method b. Why?
b = i; // 2nd problem: b can't be assigned to i although i references an object of class B?
b = (B)i; // why does this work fine...
a = (A)i; // 3rd problem: ...but this here doesn't?
}
}
So here are my questions:
First Problem
Why can't i.b() be called?
i points to the same object as b, an object of class B which does have a method b.
So why does i.a() call the right method (the one that prints out "B") but i.b() doesn't resolve at all?
Does the fact that i was declared as being of type I (an interface) have anything to do with that? Does this mean that in an assignment X x = new Y() where Y extends X, one can only ever call methods on x that are already declared in X, and not just specific to Y?
Second Problem
Why can't b be assigned to i although i references an object of class B? b and i already reference the same object, don't they? So why does it cause an error if I try to assign b to i - the end result of which should be identical to the state of the program before that assignment, unless I'm missing something significant.
Third Problem
Why can I cast i to type B now although I couldn't assign b to i earlier, and why doesn't casting i to A work?
I'm assuming my confusion is somehow rooted in an unclear distinction between the reference variables and the objects they're referencing, as well as the differences between the types of these variables and objects. I just can't quite explain these occurrences - and in particular the first problem confuses me a lot.
For the first problem:
You can use the interface reference to call only the methods it declares
For the second problem:
You can use interface reference to invoke methods in the classes that implement the interface. However, there is no use to assign interface reference to a class reference since interface reference doesn't have any methods that can be invoked.
for the third problem:
You have assigned previously
i=b
and hence
b=(B)i
works fine.
However,
a=(A)i
wouldn't work because i stores b and not a
First of all, learn Java (and/or OO (object oriented)) programming...
Variable i is a reference to an object instance that implements interface I. Method b() was not declared in interface I, thus it is not visible through i.b().
To be able to call it, i needs to be casted, EG: ((B) i).b()
Variable b is a reference to an object that is an instance of class B, and cannot be assigned to any reference that itself is not declared as an instance of B.
Again, a cast needed, EG: b = (B) i
Class B is not a child of class A. They both implement interface I, but A is not parent of B.
It's not a problem at all but It's behavior of inheritance and polymorphism.
Please note that when you
I i = new A();
Left hand side (I) will tells compiler which all methods it can call using that reference.
Right hand side (A) will tells the runtime which method should execute using that method call
So in your case
1 Problem
you can not call b() since b() is not there in inteface I
2 Problem
you are casting interface to object b and then calling b() so its working fine.
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.
Consider this:
class A {
int x =5;
}
class B extends A{
int x =6;
}
public class CovariantTest {
public A getObject() {
return new A();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
CovariantTest c1 = new SubCovariantTest();
System.out.println(c1.getObject().x);
}
}
class SubCovariantTest extends CovariantTest {
public B getObject(){
return new B();
}
}
As far as I know, the JVM chooses a method based on the true type of its object. Here the true type is SubCovariantTest, which has defined an overriding method getObject.
The program prints 5, instead of 6. Why?
The method is indeed chosen by the runtime type of the object. What is not chosen by the runtime type is the integer field x. Two copies of x exist for the B object, one for A.x and one for B.x. You are statically choosing the field from A class, as the compile-time type of the object returned by getObject is A. This fact can be verified by adding a method to A and B:
class A {
public String print() {
return "A";
}
}
class B extends A {
public String print() {
return "B";
}
}
and changing the test expression to:
System.out.println(c1.getObject().print());
Unless I'm mistaken, methods are virtual in java by default, so you're overriding the method properly. Fields however (like 'x') are not virtual and can't be overriden. When you declare "int x" in B, you are actually creating a totally new variable.
Polymorphism doesn't go into effect for fields, so when you try and retrieve x on an object casted to type A, you will get 5, if the object is casted to type B, you will get 6.
When fields in super and subclasses have the same names it is referred to as "hiding". Besides the problems mentioned in the question and answer there are other aspects which may give rise to subtle problems:
From http://java.sun.com/docs/books/tutorial/java/IandI/hidevariables.html
Within a class, a field that has the
same name as a field in the superclass
hides the superclass's field, even if
their types are different. Within the
subclass, the field in the superclass
cannot be referenced by its simple
name. Instead, the field must be
accessed through super, which is
covered in the next section. Generally
speaking, we don't recommend hiding
fields as it makes code difficult to
read.
Some compilers will warn against hiding variables