Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java generic cast, non direct

I found something strange about the casts in Java, i never saw that before. The cast is actually not done where you've programmed it in a generic method.

Testing the strange thing.

On a HashMap:

HashMap<String,Object> map = ...
map.put("hello", "World");
System.err.println((Integer)map.get("hello")); //  -----> ClassCastException

On a map Wrapper

MapWrap wrap = ...
wrap.put("hello", "World");
System.err.println(wrap.get("hello",Integer.class)); // -----> don't cast, print World (i guess because println receives an Object reference but the cast should be done before that).
System.err.println(wrap.get("hello", Integer.class).toString()); // -----> print World + ClassCastException

Code of methods:

private <T> T get(String key, Class<T> c){
    return (T)map.get(key);
}

private Object get(String key){
    return map.get(key);
}

Does someone know if that mechansim has a name or know something about it ?

Thanks

like image 860
kazgul Avatar asked Nov 22 '25 10:11

kazgul


2 Answers

The cast:

(T) map.get(key);

doesn't do anything at all because of type erasure. The method MapWrap.get() will get erased to:

private Object get(String key, Class<T> c){
    return map.get(key);
}

which will always work. A cast to Integer would only be inserted where you assigning the result of this method to, and since in the first MapWrap example you're passing it to a method that expects an Object parameter, this doesn't happen.

In the second case, you're trying to call the method Integer.toString(), so a cast to Integer gets inserted, and fails.

You're already passing in the class object, the correct way to do a "generic cast" is this:

private <T> T get(String key, Class<T> c){
    return c.cast(map.get(key));
}
like image 88
millimoose Avatar answered Nov 24 '25 01:11

millimoose


Types parameters are erased upon compilation. So a cast such as (T) becomes (Object) in the executable, hence the first behavior you're getting.

Type parameters are used only to perform compile-time typing and typechecking.

On the second line however, I think the compiler generates a call to the Integer.toString() method, so a cast is needed, hence the exception.

See: Type Erasure in the Java tutorial.

like image 31
ChrisJ Avatar answered Nov 24 '25 01:11

ChrisJ



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!