Java casting in interfaces
JavaInterfaceCastingJava Problem Overview
Can someone please explain to me how the compiler does not complain in the first casting, but does complain in the second?
interface I1 { }
interface I2 { }
class C1 implements I1 { }
class C2 implements I2 { }
public class Test{
public static void main(String[] args){
C1 o1 = new C1();
C2 o2 = new C2();
Integer o3 = new Integer(4);
I2 x = (I2)o1; //compiler does not complain
I2 y = (I2)o3; //compiler complains here !!
}
}
Java Solutions
Solution 1 - Java
When you cast o1
and o3
with (I2)
, you tell the compiler that the class of the object is actually a subclass of its declared type, and that this subclass implements I2
.
The Integer
class is final, so o3
cannot be an instance of a subclass of Integer
: the compiler knows that you're lying. C1
however is not final, so o1
could be an instance of a subtype of C1
that implements I2
.
If you make C1
final, the compiler will complain too:
interface I1 { }
interface I2 { }
final class C1 implements I1 { }
class C2 implements I2 { }
public class Test{
public static void main(){
C1 o1 = new C1();
C2 o2 = new C2();
Integer o3 = new Integer(4);
I2 y = (I2)o3; //compiler complains here !!
I2 x = (I2)o1; //compiler complains too
}
}
Solution 2 - Java
According to JLS chapter 5
5.5.1. Reference Type Casting
> Given a compile-time reference type S (source) and a compile-time reference type T (target), a casting conversion exists from S to T if no compile-time errors occur due to the following rules. > If T is an interface type: > > If S is not a final class (§8.1.1), then, if there exists a supertype X of T, and a supertype Y of S, such that both X and Y are provably distinct parameterized types, and that the erasures of X and Y are the same, a compile-time error occurs. > > Otherwise, the cast is always legal at compile time (because even if S does not implement T, a subclass of S might). > > If S is a final class (§8.1.1), then S must implement T, or a compile-time error occurs.
Solution 3 - Java
That's because class Integer
is final and C1
is not. Thus, an Integer object cannot implement I2, while a C1 object could if it is an instance of a subclass of C1 that implements I2.
Solution 4 - Java
According to JLS 5.5.1 - Reference Type casting, the rule(s) apply:
-
If T is a class type, then either |S| <: |T|, or |T| <: |S|. Otherwise, a compile-time error occurs.
I2 y = (I2)o3; //compiler complains here !!
In this case, an Integer
and I2
are unrelated in any way, so a compile-time error occurs. Also, because Integer
is final
, there is no relation between Integer
and I2
.
I2
and I1
can be related due to both being a marker interface (there are no contract).
As for the compiled code, the rule follows:
- If S is not a final class (§8.1.1), then, if there exists a supertype X of T, and a supertype Y of S, such that both X and Y are provably distinct parameterized types, and that the erasures of X and Y are the same, a compile-time error occurs.
S
is o1
and T
is I2
.
Hope this helps.