Reputation: 51
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 this
or 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?
Upvotes: 3
Views: 205
Reputation: 16
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.
Upvotes: 0
Reputation: 7290
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
.
Upvotes: 1
Reputation: 20914
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.
C
.B
since B
is the superclass of C
.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.
Upvotes: 2
Reputation: 1720
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.
Upvotes: 1
Reputation: 2000
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
Upvotes: 1