I found a way to add Floats to an Integer array through generic types. I'm curious why Java doesn't catch this in a runtime error? I tried looking through the docs for any info about this, but I haven't had any luck.
For example, say I have two ArrayLists, one containing Integers, and one containing Floats, like so:
ArrayList<Integer> listInt = new ArrayList<>();
ArrayList<Float> listFlt = new ArrayList<>();
listInt.add(6);
listInt.add(71);
listFlt.add(4.92f);
listFlt.add(20.5f);
Using generics, I can copy the Floats from listFlt into listInt through a method like this:
public static <T extends Number, S extends Number> void copy(ArrayList<T> src, ArrayList<S> dest) {
for (int i = 0; i < src.size(); i ) {
Object x = src.get(i);
dest.set(i, (S)x);
}
}
Calling it with:
ClassName.<Float, Integer>copy(listFlt, listInt);
Now, when I print listInt, it displays:
4.92
20.5
How is it possible to cast an Object as an Integer when generics are involved? And how can listInt store Floats? Thanks!
CodePudding user response:
Using generics, I can copy the Floats from listFlt into listInt through a method like this
Note that inside this method, you are casting to the type parameter S
:
dest.set(i, (S)x);
This will cause an unchecked cast warning when you compile it (which you should not ignore!).
It's allowed, but because of type erasure, the JVM will not be able to check at compile time if the cast is allowed.
This is an example of heap pollution: because of the rules of the Java language and type erasure, you get into a situation where you can add objects into an ArrayList
that are of the wrong type (in this case: you are adding Float
objects to a list that is supposed to contain Integer
objects).
When you just print the list, there is no problem, because in that case Java only needs to call toString()
on the elements of the list, and that method exists for all objects.
But when you try to get an Integer
out of the list, you will get a ClassCastException
:
ClassName.<Float, Integer>copy(listFlt, listInt);
Integer i = listInt.get(0); // ClassCastException: Float cannot be cast to Integer
It's an unfortunate consequence of a combination of the rules of Java, which are partly the way they are because of backward compatibility, and the way that Java works with generics (with type erasure).
Point to remember: Do not ignore "unchecked cast" warnings; they are a hint that there is possible heap pollution going on in your code.