So I have a map:
Map format = new HashMap();
And I would add elements to it like this:
It is because your HashMap returns a
Class
object, but the verify function expects a
Class<T>
object.
The reason you get this error is that in the first case the compiler sees that you pass it a Class object and is able to bind T to Integer at compile time, but in the second case the compiler only sees that you are passing it a Class object.
At the end of the day, you will not be able to do
Integer i = verifyType("100",format.get("Vendor Number"));
in a type-safe way, since the compiler can't know that you will get an Integer (what if someone does a format.put("Vendor Number", X.class) just before that call?)
You have to genericize your references to Class. For example:
Class<Integer> type = Integer.class
Integer i = verifyType("100",type);
would work fine.
As would:
Map<String, Class<?>> format = new HashMap<String, Class<?>>();
However, this will never work:
Integer i = verifyType("100",format.get("Vendor Number"));
Because format is not defined as:
Map<String, Class<Integer>>
If it was, the casting would work, but the design would be pointless.
The closest you can get is:
Integer i = verifyType("100",(Class<Integer>) format.get("Vendor Number"));
However, you will get a compiler warning doing it, as you must - it is an inherently unsafe cast. The compiler is taking your word for it that that format.get statement will return an integer. If you are sure of that, then that is what unsafe casts are for. If you want to get rid of the compiler warning, you could do this:
Class<?> type = format.get("Vendor Number");
Integer i = null;
if (type == Integer.class) {
i = verifyType("100", Integer.class);
} else {
//What do you want to do?
}
Change:
Class type = Integer.class
Integer i = verifyType("100",type);
to
Class<Integer> type = Integer.class
Integer i = verifyType("100",type);
By only declaring the type as 'Class', you're losing the generic parameter and the verifyType() method can't infer the class, thus the unchecked warning.
This problem:
Map<String, Class> format = new HashMap<String, Class>();
format.put("Vendor Number", Integer.class);
format.put("Vendor Dispatch", Date.class);
Integer i = verifyType("100",format.get("Vendor Number"));
can't really be solved due to type erasure. The compiler can't infer the type based on a generic parameter that is gone by runtime. This is because Java generics are little more than smoke and mirrors for casting.
Class Class
is a generic class itself. If you try
Class<Integer> type = Integer.class;
Integer i = verifyType("100", type);
it should work better. Generification of the input parameter convinces the compiler that you know what you're doing, enough to let your code compile without warning.
You can also convince the compiler by suppressing the warning using
@SuppressWarning("unchecked")
before the specific line of code or method.
It is strange for me, that your compiler on line
Integer i = verifyType("100",format.get("Vendor Number"));
complains about unchecked invocation but doesn't show an error like "Type mismatch: cannot convert from Object to Integer".
This line just doesn't make sense to me. What do you expect verifyType to return if it receives Date.class as a second parameter? Also an Integer (then the return type of verifyType is invalid)? Or a Date? If you expect a Date, how is compiler expected to know that
format.get("Vendor Number");
returns Integer.class, but
format.get("Vendor Dispatch");
returns Date.class
Invocation of
Integer i = verifyType("100",format.get("Vendor Dispatch"));
must fail, as Date is not an Integer. So, in my opinion (and in opinion of my compiler) compilation of
Integer i = verifyType("100",format.get("Vendor Number"));
must fail.