Why does Java let you cast to a collection?
This question already has an answer here:
- Java casting in interfaces 4 answers
I have a simple foo class, and I am able to cast to a collection interface (either Map or List) without any compiler error. Note that Foo class does not implement any interface or extends any other class.
public class Foo {
public List<String> getCollectionCast() {
return (List<String>) this; // No compiler error
}
public Map<String, String> getCollection2Cast() {
return (Map<String, String>) this; // No compiler error
}
public Other getCast() {
return (Other)this; // Incompatible types. Cannot cast Foo to Other
}
public static class Other {
// Just for casting demo
}
}
Why does the Java compiler not return incompatible types error when I try to cast the Foo class to a collection?
Foo does not implement Collection. I would expect an incompatible types error, because given the current Foo class signature, this cannot be a Collection.
It's not because they're collection classes, it's because they're interfaces. Foo doesn't implement them, but subclasses of it could. So it's not a compile-time error, since those methods may be valid for subclasses. At runtime, if this isn't of a class that implements those interfaces, naturally it's a runtime error.
If you change List<String> to ArrayList<String>, you'll get a compiler-time error for that, too, since a Foo subclass could implement List, but can't extend ArrayList (since Foo doesn't). Similarly, if you make Foo final, the compiler will give you an error for your interface casts because it knows they can never be true (since Foo can't have subclasses, and doesn't implement those interfaces).
The compiler doesn't prevent code from casting a type to an interface, unless it can establish for sure that the relationship is impossible.
If the target type is an interface, then it makes sense because a class extending Foo can implement Map<String, String>. However, note that this only works as Foo is not final. If you declared your class with final class Foo, that cast would not work.
If the target type is a class, then in this case it would simply fail (try (HashMap<String, String>) this), because the compiler knows for certain that the relationship between Foo and HashMap is impossible.
For reference, these rules are described in JLS-5.5.1 (T = target type - Map<String, String>, S = source type - Foo)
If T [target type] 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.
Note the bold-italic comment in the quoted text.
https://docs.oracle.com/javase/8/docs/api/java/util/List.html
All Superinterfaces: Collection, Iterable
Foo is a List is a Collection.
참고URL : https://stackoverflow.com/questions/52698154/why-does-java-let-you-cast-to-a-collection
'Nice programing' 카테고리의 다른 글
| jasper를 얻기 위해 jrxml을 어떻게 컴파일합니까? (0) | 2020.11.17 |
|---|---|
| fetch vs. [] when working with hashes? (0) | 2020.11.16 |
| C# Convert a Base64 -> byte[] (0) | 2020.11.16 |
| How to find index position of an element in a list when contains returns true (0) | 2020.11.16 |
| Matplotlib에서 3D 큐브, 구 및 벡터 플로팅 (0) | 2020.11.16 |