简体   繁体   中英

Casting Number to double primitive

I'm trying to access a HashMap<String, Number> via reflection:

Serializable obj; //here goes the HashMap
String name;
...
return (double)obj.getClass().getDeclaredMethod("get", Object.class).invoke(obj, name);

but so far all I got is a casting error caused by the line above:

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Double

Indeed, the map value that was accessed by the key name was Integer .So I've changed the line to:

return obj.getClass().getDeclaredMethod("get", Number.class).invoke(obj, name).doubleValue();

but that didn't work out either. I even got doubleValue() underlined as "undefined for the type Object" (but why Object if I have Number.class?).

I'm not sure what casting rules I'm breaking. Can someone, please, help me if my map entries have various number values ( Integer , Float , Double ) but I need the method to return a double value (primitive).

PS It's not really a duplicate. My question is more general. But thank you for your input. I forgot that invoke always returns Object.

The working code is:

return ((Number)obj.getClass().getDeclaredMethod("get", Object.class).invoke(obj, name)).doubleValue();

You have the wrong assumption that there was a relationship between the Class object you pass to getDeclaredMethod and the return type of Method.invoke . The Class objects you pass to getMethod or getDeclaredMethod describe the parameter types of the method, not the return type. Further, while you may pass arguments of a subtype of the declared parameter type, you have to specify exactly the declared parameter type.

The parameter type of Map.get is Object , invariably, so you have to specify Object.class , regardless of which actual key you will pass to invoke .

Further, due to type erasure, the reflective return type will always be Object , regardless of the actual Map 's parametrization. Not that it matters, Method.invoke 's declared return type is always Object , as different Method instances may represent different methods.

So when you have a HashMap<String, Number> , you can rely on the returned objects to be Number instances, but not necessarily Double instances. As you experienced, there could be Integer instances. So what you have to do, is to type-cast to Number , followed by invoking doubleValue() :

return ((Number)obj.getClass().getDeclaredMethod("get", Object.class)
        .invoke(obj, name)).doubleValue();

That said, if you know that the object implements the Map interface, there is no reason to use Reflection at all:

return ((Number)((Map<?,?>)obj).get(name)).doubleValue();

does the job much more efficient.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM