Java casting question

C

Chad

Given the following...

class X {
void f1() { System.out.println("XXX");}
void f2() { System.out.println("AAA"); f1();}
}

class Y extends X {
void f1() { System.out.println("YYY"); }
}

class Z extends X {
void f1() { System.out.println("ZZZ"); }
}
public class Main {

static void g(X a) {
a.f2();
}
public static void main(String[] args) {
X x = new X();
Y y = new Y();
Z z = new Z();

Object obj = new Y();
((X) obj).f2();
g(z);
//y = (Y)x;
}

}

I get the following output..

AAA
YYY
AAA
ZZZ


The question is about

Object obj = new Y();
((X) obj).f2();


How come YYY, but not XXX, gets printed on the second line? Both f1()
and f2() are in class X. So shouldn't f1() also have been casted to
(type) X?

Chad
 
A

Arne Vajhøj

Given the following...

class X {
void f1() { System.out.println("XXX");}
void f2() { System.out.println("AAA"); f1();}
}

class Y extends X {
void f1() { System.out.println("YYY"); }
}

class Z extends X {
void f1() { System.out.println("ZZZ"); }
}
public class Main {

static void g(X a) {
a.f2();
}
public static void main(String[] args) {
X x = new X();
Y y = new Y();
Z z = new Z();

Object obj = new Y();
((X) obj).f2();
g(z);
//y = (Y)x;
}

}

I get the following output..

AAA
YYY
AAA
ZZZ


The question is about

Object obj = new Y();
((X) obj).f2();


How come YYY, but not XXX, gets printed on the second line? Both f1()
and f2() are in class X. So shouldn't f1() also have been casted to
(type) X?

((X) obj).f2();

and

((Y) obj).f2();

should give the same output.

Virtual methods are stored in the object and it really
does not matter what type the ref is declared to.

Arne
 
L

Lew

Arne said:
Chad said:
Given the following...

class X {
void f1() { System.out.println("XXX");}
void f2() { System.out.println("AAA"); f1();}
}

class Y extends X {
void f1() { System.out.println("YYY"); }
}

class Z extends X {
void f1() { System.out.println("ZZZ"); }
}
public class Main {

static void g(X a) {
a.f2();
}
public static void main(String[] args) {
X x = new X();
Y y = new Y();
Z z = new Z();

Object obj = new Y();
((X) obj).f2();
g(z);
//y = (Y)x;
}

}

I get the following output..

AAA
YYY
AAA
ZZZ


The question is about

Object obj = new Y();
((X) obj).f2();


How come YYY, but not XXX, gets printed on the second line? Both f1()
and f2() are in class X. So shouldn't f1() also have been casted [sic] to
(type) X?

The past participle of "to cast" is "cast", not "casted".

Casting from a type to a supertype is automatic, so the '(X)' cast in your code is superfluous. Since 'Y' /is-an/ 'X',. your 'obj' of type 'Y' is already of type 'X'; no cast needed. (In Java, casting to a parent type is "upcasting" or "widening", and comes for free. Casting to an extending type is "downcasting" or "narrowing", and requires a cast operator.)

And no, you should not see the 'X' version of the output from your 'Y' instance, for the reason Arne explained:
((X) obj).f2();

and

((Y) obj).f2();

should give the same output.

Virtual methods are stored in the object and it really
does not matter what type the ref is declared to.

To put it another way, the object instance "knows" its own type. You cannot call a method on the supertype that exists only in the subtype, but if you call a method that exists in the supertype that the instance's subtype overrides, you will get the overridden version.

This is a key to how object-oriented programming works.

Instances own their own members (methods and variables); the declared type only controls what the compiler is allowed to see, not how the method behaves.

Arne referred to "virtual methods". That means the method call is dispatched to the instance, not literally called from the reference. The instance uses its own version of the method - the parent type's if not overridden, the derived type's if it is overridden.

Read the Java Language Specification (JLS) for the gory details.
 
T

Travers Naran

AAA
YYY
AAA
ZZZ


The question is about

Object obj = new Y();
((X) obj).f2();


How come YYY, but not XXX, gets printed on the second line? Both f1()
and f2() are in class X. So shouldn't f1() also have been casted to
(type) X?

You're not understanding what casting in Java means, nor how Java
implements methods.

You seem to be thinking that (X)obj _converts_ obj into an instance of X
complete with X's methods. That is incorrect. Obj will _always_
remember it is Y and any method calls on Obj will go to Y's methods
first. Casting can _never_ change that. Ever.
 
A

Andreas Leitgeb

Lew said:
To put it another way, the object instance "knows" its own type.
You cannot call a method on the supertype that exists only in the
subtype, but if you call a method that exists in the supertype that
the instance's subtype overrides, you will get the overridden version.

At compile-time, the static type determines which method signature is
picked, but at runtime the actual implementation for that signature
is picked based on the object's actual type.

Here is another example:

class Test {
void f1(Test o) { System.out.println("Test.f1(Test)"); }
}
class SubTest extends Test {
void f1(Test o) { System.out.println("SubTest.f1(Test)"); }
void f1(SubTest o) { System.out.println("SubTest.f1(SubTest)"); }
}
public class Main {
public static void main(String[] args) {
SubTest st = new SubTest();

st .f1(st);
((Test) st) .f1(st);
}
}

Output:
SubTest.f1(SubTest)
SubTest.f1(Test)

This shows, how the compiler settles on a method:
for the first call, the compiler sees static type SubTest, and
from among the two over*loads* picks the one most specifically
matching the static type of the arguments: f1(SubTest).
for the second call, the compiler sees static type Test, and
Test only has one version f1(Test), so the compiler picks that.
At runtime, however, SubTest.f1(Test) is called, as the object
itself is a SubTest.
This is a key to how object-oriented programming works.
yup


PS: (for Lew)
Lew said:
Casting from a type to a supertype is automatic,
so the '(X)' cast in your code is superfluous.
The premise did not apply, thus neither does the conclusion.
 
A

Arne Vajhøj

To put it another way, the object instance "knows" its own type. You cannot call a method on the supertype that exists only in the subtype, but if you call a method that exists in the supertype that the instance's subtype overrides, you will get the overridden version.

This is a key to how object-oriented programming works.

Instances own their own members (methods and variables); the declared type only controls what the compiler is allowed to see, not how the method behaves.

It may be worth noting that even though in Java all (non static)
methods are virtual then there are other OO languages like
C++ and C# where one need to explicit declare them virtual.

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top