Consider the following code:
import java.math.BigDecimal;
class Scratch {
public static class Test<N extends Number> {
public void foo(Class<N> numberClass) {
System.out.println(numberClass);
}
public void bar() {
foo(BigDecimal.class);
}
}
public static void main(String[] args) {
Test<Number> t = new Test<>();
t.bar();
}
}
This fails to compile on line 12 (the call to foo()
) with incompatible types: java.lang.Class<java.math.BigDecimal> cannot be converted to java.lang.Class<N>
. I don't get it, because the generic N
extends Number
, and so I should be able to pass BigDecimal.class
to a method which takes a Class<N>
parameter. TIA for any thoughts!
CodePudding user response:
Suppose a caller did:
var t = new Test<Integer>();
t.bar();
then, bar()
would pass a BigDecimal
to foo()
, which expects an Integer
.
CodePudding user response:
The short answer really is that BigDecimal
is not necessarily N
. It is a little confusing because BigDecimal
is within the <N extends Number>
bounds, but the current instance's generic type argument can be any type that extends Number
, but the bar
method assumes BigDecimal
.
Check this slightly modified version of the method:
public void bar() {
new Test<BigDecimal>().foo(BigDecimal.class);
}
That method compiles. Why? Becuase Test<BigDecimal>()
has BigDecimal
as type argument.
When you call foo(BigDecimal.class)
, you're assuming that this
was instantiated with BigDecimal
as type argument, which is not always true, and the the compiler is preventing a bug.
The error in your code would be similar to a hypothetical bar()
method in ArrayList<T>
that does add("string")
, which would be wrong for the same reason (the actual array list instance may be created to hold integers, not strings, so the inside code shouldn't make assumptions)