When coding in Kotlin/Java, I stumbled onto something rather odd while using casting and generics.
It seems to be possible to have the type system believe a list is of the type List<Foo>
, while it is actually a List<Object>
.
Can anyone explain to me why this is possible?
Here is an example in both Kotlin and Java of the issue:
Example in Kotlin
fun <T> test(obj: Any): List<T> {
val ts = ArrayList<T>()
ts.add(obj as T)
return ts
}
fun <T> test2(obj: Any): T {
return obj as T
}
fun <T> test3(obj: Any): List<T> {
val ts = ArrayList<T>()
ts.add(test2(obj))
return ts
}
fun main(args: Array<String>) {
val x = test<Double>(1) // Returns a list of Integers and doesn't error
println(x)
val y = test2<Double>(1) // Casts the Int object to a Double.
println(y)
val z = test3<Double>(1) // Returns a list of Integers and doesn't error.
println(z)
}
Example in Java
public class Test {
public static <T> List<T> test(Object obj){
ArrayList<T> ts = new ArrayList<>();
ts.add((T) obj);
return ts;
}
public static <T> T test2(Object obj){
return (T) obj;
}
public static <T> List<T> test3(Object obj){
ArrayList<T> ts = new ArrayList<>();
ts.add(test2(obj));
return ts;
}
public static void main(String[] args) {
List<Double> x = test(1); // Returns a list of Integers and doesn't error
System.out.println(x);
// Double y = test2(1); // Errors in java an Integers cannot be converted into a Double.
// System.out.println(y);
List<Double> z = test3(1); // Returns a list of Integers and doesn't error.
System.out.println(z);
}
}