I have the following code:
import java.util.*;
public class SellTransaction extends Transaction {
private Map<String,? extends Object> origValueMap;
public SellTransaction(Map<String,? extends Object> valueMap) {
super(Transaction.Type.Sell);
assignValues(valueMap);
this.origValueMap=valueMap;
}
public SellTransaction[] splitTransaction(double splitAtQuantity) {
Map<String,? extends Object> valueMapPart1=origValueMap;
valueMapPart1.put(nameMappings[3],(Object)new Double(splitAtQuantity));
Map<String,? extends Object> valueMapPart2=origValueMap;
valueMapPart2.put(nameMappings[3],((Double)origValueMap.get(nameMappings[3]))-splitAtQuantity);
return new SellTransaction[] {new SellTransaction(valueMapPart1),new SellTransaction(valueMapPart2)};
}
}
The code fails to compile when I call valueMapPart1.put and valueMapPart2.put, with the error:
The method put(String, capture#5-of ? extends Object) in the type Map is not applicable for the arguments (String, Object)
I have read on the Internet about generics and wildcards and captures, but I still don’t understand what is going wrong. My understanding is that the value of the Map‘s can be any class that extends Object, which I think might be redundant, because all classes extend Object. And I cannot change the generics to something like ? super Object, because the Map is supplied by some library.
So why is this not compiling? Also, if I try to cast valueMap to Map<String,Object>, the compiler gives me that ‘Unchecked conversion’ warning.
Thanks!
If the library specifies
extendsthen they are explicitly disallowingput. You should defensively copy before modifying, since they can quite legitimately change their return type to be immutable in a new version. If copying is expensive, then you can try creating a map type that is of type<String, Object>that first queries their map, and then queries some map you create that has your local modifications.If you do know that their return type is immutable and that you solely own it, then the
@SuppressWarnings("unchecked")annotations is a legitimate way to work around the warning, but I would double check those assumptions and comment extensively.To understand
extendsvssuper, look at it this way.Since the value can be any type that extends
Object, the following is valid.So
putdoesn’t really work with theextendsboundary types.But it works perfectly well with reading operations like
get:If you want a map to primarily use with “put” instead of “get”, then you can use “super” instead of extends as in: