I'm scratching my head over how this example works and seems to print appropriately .
public class Test {
static class Shape {
public String toString() {
return "Shape";
}
}
static class Circle extends Shape {
public String toString() {
return "Circle";
}
}
static class Square extends Shape {
public String toString() {
return "Square";
}
}
public static void wildCardVarArgs(ThreadLocal<? extends Shape>... list) {
for (ThreadLocal<? extends Shape> s : list) {
System.out.println(s.get().toString());
}
}
public static void test() {
ThreadLocal<Shape> shape = new ThreadLocal<>();
shape.set(new Shape());
ThreadLocal<Square> square = new ThreadLocal<>();
square.set(new Square());
ThreadLocal<Circle> circle = new ThreadLocal<>();
circle.set(new Circle());
wildCardVarArgs(shape, square, circle);
}
}
Calling tests will print:
"Shape"
"Square"
"Circle"
Intuitively this makes sense, as the method signature is described as accepting any amount of arguments as long as they are of type ThreadLocal with a type of any extension of Shape. So passing in a ThreadLocal<Square>
along with ThreadLocal<Circle>
fits the bill.
But how does this compile in such a way that runtime can determine the proper overload of string? My hazy understanding of generic type erasure makes it seem like this sort of method signature should not be possible to even compile. I would've thought that the signature for wildCardVarArgs becomes something along the lines of wildCardVarArgs(ThreadLocal[])
in byte code, which seems like execution should run into a ClassCastException. But the more I think about it, the more confused I get.
Anyone able to make sense of this and what does compiling do to a Bounded Wildcard type of ThreadLocal?