1

I've been trying to understand casting in Java and how it affects the references. I've come up on this particular example:

public interface A1{
      public void foo();
};

public class A2{
      public void bar();
      public static void main( String[] args )
      {
         A2 a = new B();
         A1 c = (A1)a;
         c.foo();
      }
};

public class B extends A2 implements A1{
      public void foo(){ System.out.println("This is B"); }
}

It prints "This is B", but i'm not sure why. This is how I understand this currently: a is a reference to an object of type A2, but during runtime, it points to a heap object which has the properties of B, but a only "sees" the properties of A2. But the types are already determined during compilation, so the cast tries to cast A2 to A1, which it can't do. Obviously I'm wrong, but I can't figure out why. Any help will be appreciated.

Xsy
  • 193
  • 7
  • Dynamic type vs. static type - must have come up several times. – laune Jul 07 '14 at 15:50
  • The type is indeed `A1` but when `foo()` is called, the call is made to the object's `foo()` which is the implementation in `B` – Nir Alfasi Jul 07 '14 at 15:51
  • possible duplicate of [Understanding inheritance and abstract classes in Java](http://stackoverflow.com/questions/4414257/understanding-inheritance-and-abstract-classes-in-java) – laune Jul 07 '14 at 15:54
  • Method calls always use the actual type ("run-time type") with which the object is created. You cannot change which method is called using a cast. _However, data members follow a different rule._ If you have a class `A` that defines a member field `m`, and a subclass `B` that defines its own separate member field `m` (**very** bad practice), if you have an object whose run-time type is `B`, you can access the `m` defined in `A` by casting the object to `(A)`. – ajb Jul 07 '14 at 16:07
  • possible duplicate of [Casting to Superclass, and Calling Overriden Method](http://stackoverflow.com/questions/21613540/casting-to-superclass-and-calling-overriden-method) – ajb Jul 07 '14 at 16:11

4 Answers4

3

Casting conceptually has two components,

  1. At runtime the JVM ensures that the object is of that type, and will error with a ClassCastException if it is not
  2. At compile time, it tells the compiler to allow use of the methods/fields of that class. Note that if the object turns out to not be of that type at runtime, then it will error at runtime.

What casting does not do, is change the type of the actual object at runtime.

In your example you called new B(); that means after casting a reference from B to A1, then the object is still an instance of B. Given that foo() is declared on A1, and B extends foo then the compiler is happy (it passes 2 above). At runtime the JVM will scan B looking for the method of foo, it checks B before A1 because the object was created as type B. It did not change its type since new was called.

Chris K
  • 11,622
  • 1
  • 36
  • 49
2

Casting checks are always made at runtime (see caveat in next paragraph), your reference points to an object of type B, therefore when you get to the casting bit, the VM will see a reference to an object of B, which can be safely cast. Note that casting doesn't actually change the object, it just ensures that the rest of the code calls methods which are available in the original object.

The caveat is that if it can be seen at compile time that the cast is definitely NOT possible, you do get a compile error.

String foo = "x";
Integer i = (Integer)foo; //throws a compile time error because `String` is final and `Integer` isn't its supertype.

But:

Object foo = "x";
Integer i = (Integer)foo; //this will only throw a runtime exception because from the compiler's point of view, `foo` may or may not be an integer.
biziclop
  • 48,926
  • 12
  • 77
  • 104
0

The type of the variable that holds the reference has nothing to do with what the method implementations resolve to. In Java, all methods are implicitly virtual, meaning that they get looked up by the actual type of the object (instead of the type of the referring variable) every time. Since c actually points to an instance of B, it's B.foo() that gets called.

Note that this doesn't necessarily hold true for all languages - in C#, for example, methods are only virtual if you explicitly declare them as such and so i its default behavior would match what you were thinking. Java, however, is always virtual.

tophyr
  • 1,658
  • 14
  • 20
0

Reference comes into picture only during compile time or in case of static methods or behaviors.

When you are creating an object, method or behavior will depend on the whose object you have created rather than whose reference you have used.This is called polymorphism.

For example lets take an example of real life entities ---

When you rent a house, you ask a broker to find a house for you, which is your reference.but the person whom house belong, the land-lord is the actual object whom you are requesting. so it is the land-lord who gives you house on rent and not the broker.

Abhi
  • 386
  • 2
  • 5
  • 21