user42155
user42155

Reputation: 49665

Casting reference variable in Java

I have something unclear concerning casting reference variable in Java.

I have two classes A and B. A is the super class of B. If I have the two objects, and then the print statement:

A a = new A(); //superclass

B b = new B(); //subclass

System.out.println ((A)b);

then what exactly is happening when the println method is executed?

I know that because B is a subclass of A, I am allowed to make the following cast:

A a2 = (A)b;

I also know that when println takes a reference variable as argument, then the toString() method of the class, which has created the object-argument, is invoked (implicitly). This is so, because the method println() is looking for an argument of type String, and the toString() method represent the object as a string. And even if we don't write toString(), the method is invoked - implicitly. So, the following two statements are equivalent:

System.out.println (b);

System.out.println (b.toString());

So, my question is: what is the implicit action taken when we have

System.out.println ((A)b); 

?

I suppose that the type of the reference variable b is automatically changed from B to A. The variable should still be pointing to the same object - the one created with

B b = new B();

but just the type of b would be now changed. Is this correct? Another question: even though I have changed the type of b to the type of the superclass, are the overriden methods in the subclass going to be called, and not those of the superclass?

Thanks a lot.

Regards

Upvotes: 3

Views: 10469

Answers (8)

da7
da7

Reputation: 119

question: even though I have changed the type of b to the type of the superclass, are the overriden methods in the subclass going to be called, and not those of the superclass?

in this case the method of subclass b is called ; to convincingly understand why; you may relate to the following real world scenario

consider a parent class Father exhibiting a behaviour(method): height defined as

the father is tall ;height = 6'2"

Son is a child class inheriting the height behavior from Father ;as a result he is also tall; height being 6' clearly overriding the behaviour

whenever your subclass Son calls the behavior height on his name he displays the overridden behavior i.e his own height 6' .

Upvotes: 0

Jeet Singh Parmar
Jeet Singh Parmar

Reputation: 727

I think when we use reference variable in java and by using this variable we can assign a object of any class type. most of the cases we create a reference variable of Interface and abstract class because we can't create the object of interface and abstract class so assign the object of class in reference variable of Interface or abstract class. Ex-

Interface X {
 public abstract void xx();
 public abstract void yy();
}

Class XXX implements X {
   ...........
}

Class XY extends XXX {
  X xy = new XXX();
} 

here xy is a reference of Interface X and assign the object of Class XXX in the reference of Interface.

so according to my point of view by using reference variable we can also use interface to participate in Object creation.

Upvotes: 1

Robin
Robin

Reputation: 24262

The casting, as has been mentioned, is irrelevant in this case due to overridden methods being dynamically bound. Since the toString is present in all objects it meets this condition and thus the object type and method to call are determined at runtime.

Please note though, this is NOT the case with all methods since only overridden methods are dynamically bound. Overloaded methods are statically bound. Many of the answers here mention that java methods are always dynamically bound, which is incorrect.

See this question for a more detailed explanation.

Upvotes: 0

Uri
Uri

Reputation: 89729

The cast has no impact in this case.

The System.out.println(XXX) takes parameters of different types (multiple overloaded versions) but in this case you would get the version that takes Object. Since every object in Java supports toString(), toString is invoked on the actual argument, no matter what it is.

Now, since all methods in Java are dispatched dynamically, the version that runs is the version that corresponds to the dynamic type. Casting an object of B to A only changes the static (declared) type of the expression. The dynamic type (what's really in there) is still a B. Therefore, the version in B gets invoked.

Upvotes: 4

Adrian Pronk
Adrian Pronk

Reputation: 13906

There are many declarations of println(...) in the PrintStream class (which is the type of System.out).

Two of them are:

void println(String x)
void println(Object x)

When you call println((A)b) the compiler chooses to call println(Object) because A is not String (or any of the other types that println supports). When you call println(b.toString()), the compiler chooses println(String) because you are passing a String.

In your case, casting b to A has no effect since println() doesn't have a declaration for either A or B types. But the cast will still occur (because you asked for it), or maybe it won't because the compiler optimises it away as it knows it is redundant and it can't fail and has no effect.

It is not idiomatic to write:

A a2 = (A)b;

as this is redundant since B is a subclass of A. It may be that the compiler will optimise away the cast (which is a run-time operation to check whether an object is of a particular type, never to change it's type).

Once an object of type B is constructed, it's type never changes. It is always a B:

class B extends/implements A {...}
B b = new B();   // construct a B
A a = b;         // assign a B to an A variable, it's superclass
A a = (A) b      // as above including check to see that b is an A (redundant, may be optimised away).

B b = a;         // Syntax error, won't compile
B b = (B) a      // Will check whether a is of type B then assign to variable b

In the last case, since B is a subclass of A, it may be that a holds an instance of B and the cast will succeed. Or it may be that a holds an instance of some other class that extends/implements/is A and isn't a B and you'll get a ClassCastException.

So since an object of type B always retains it's identity (it's "B"-ness) then any (instance-) methods called on that object will always call B's implementation regardless of whether the variable through which you access the object was declared as A or B.

Remember, you can only call methods that are declared in the class that the variable is defined as.

So for example, if B declares a method b_only() then the compiler won't allow you to write a.b_only(); you could write ((B)a).b_only() though.

Upvotes: 3

Bill K
Bill K

Reputation: 62769

Always think of your object as the type it's instantiated as (B in your case). If it's upcast to A think of it as--hmm--think of it as B putting on A clothes. It may look like an A, and you may not be able to do any of the nice B things you want to do, but inside the clothes it's still a B--the clothes don't change the underlying object at all.

So the summary would be--you can only call the methods in A, but when you call it, it goes straight through and executes it as it would if it was a B.

Upvotes: 1

yawmark
yawmark

Reputation: 1944

Is this correct?

Sort of. The result of the casting expression would be of the A type. The type of the 'b' variable will always remain of type B.

Another question: even though I have changed the type of b to the type of the superclass, are the overriden methods in the subclass going to be called, and not those of the superclass?

The instance methods of the underlying object will be called. Example:

class Foo {
    public static void main(String[] args) {
        B b = new B();
        assert "B".equals(((A) b).m());
    }
}

class A {
    String m() { return "A"; }
}

class B extends A {
    String m() { return "B"; }
}

Upvotes: 1

jpalecek
jpalecek

Reputation: 47762

Since Java methods all have dynamic dispatch, which function gets called doesn't depend on the static type of the reference. Therefore, the results will be the same with or without the cast. [The results could be different if you were downcasting - the casting version could throw an exception]

Upvotes: 1

Related Questions