Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Casting "with" Interface [duplicate]

Tags:

interface I{}
class A implements I{}
class B{}

First:

I[] arr = new A[10];
arr[0] = (I) new B(); // will produce ClassCastException at runtime

Second: wherein if I use concrete class

I[] arr = new A[10];
arr[0] = (A) new B(); // will produce compile-time error

What's the difference if in my first example,(I) new B(), the java compiler should produce compile-error as well?

Isn't it that the java compiler should be able to distinguish that it is also an "inconvertible type"? Especially when the new operator comes immediately?

Is there any instance/chance that it will be possible that creating that new instance of B could produce a convertible type of type I?

I know at some point, that the Java compiler should not immediately say that it is a compiler error, like when you do this:

I i = (I) getContent(); // wherein getContent() will return a type of Object

Edit:

Let me clarify this question why it is not a possible duplicate of this: Cast reference of known type to an interface outside of type's hierarchy

The intention of this question is not because I am not aware of what will be the result of or what is something wrong with something, etc.

I just want to know a "more detailed explanation in a technical way" of why does the JVM behave that way or why does Java came up with that kind of decision of not making that kind of scenario a compile-time error.

As what we all know, it is always better to find "problematic code" at compile-time rather than at run-time.

Another thing, the answer I am looking for was found here on this thread not on those "duplicates?".

like image 488
kev Avatar asked Jun 11 '14 08:06

kev


2 Answers

The rules for what casts are compile-time legal only take into account the static types.

When the Java compiler analyzes the expression (I) new B(), it sees that the static type of the expression new B() is B. We can tell that new B() can't possibly be an instance of I, but the compile-time analysis rules can't tell that the object isn't actually an instance of a subclass of B that implements I.

Thus, the compiler has to let it through. Depending on how sophisticated the compiler is, it might detect the oddity and issue some sort of warning, but in the same way 1/0 isn't a compile-time error, this can't be a compile-time error.

like image 121
user2357112 supports Monica Avatar answered Oct 10 '22 16:10

user2357112 supports Monica


The difference in this situation is obviously that I is an interface, which could be implemented. This means, that even though B has nothing to do with I, there could be a subclass of B, that implements the interface I. Will illustrate this with an example:

interface I{}
class A implements I{}
class B{}
class C extends B implements I{}

I[] arr = new A[10]; // valid, cause A implements I
B b = new C(); // Valid because C is a subclass of B
arr[0] = (I) b; // This won't produce ClassCastException at runtime, because b
                // contains an object at runtime, which implements I
arr[0] = (I) new B(); // This will compile but will result in a ClassCastException
                      // at runtime, cause B does not implement I

It's important to distinguish the difference between static and dynamic types. In this case the static type of the variable b is B, but it has the dynamic type (the runtime type) C, where new B() does also have the static type B, but the dynamic type is also B. And as in some cases a cast from B to I won't result in exceptions (as in this scenario), the compiler allows such casts but only to an interface type.

Now take a look at the following scenario:

I[] arr = new A[10];
B b = new C(); // Valid because C is a subclass of B
A a1 = (A) b; // compile time error
A a2 = (A) new B(); // compile time error

Is it possible that a subclass of B will ever extend A and B at the same time? The answer is NO, cause you are limited to only one super class to extend in Java (where in some other OO languages this is not the case), therefore the compiler forbids it, cause there are no possible scenarios, where this will work.

like image 35
Ivaylo Toskov Avatar answered Oct 10 '22 16:10

Ivaylo Toskov