Help Java generics: cannot use “object” as parameter “? Extends object“
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)}; } }
When I call valuemappart1 Put and valuemappart2 When put, the code cannot be compiled with the following error:
The method put(String,capture#5-of ? extends Object) in the type Map is not applicable for the arguments (String,Object)
I've read about generics and wildcards and capture on the Internet, but I still don't understand what's wrong My understanding is that the value of map can be any class that extends object. I think this may be redundant because all classes extend object I can't change generics to something like that? Super object, because map is provided by some libraries
Then why not compile? In addition, if I try to convert valuemap to map < string, Object >, the compiler will give me an "unchecked conversion" warning
thank you!
Solution
If libraries specify extensions, they explicitly prohibit placement You should make defensive copies before modifying, because they can reasonably change their return type to immutable in the new version If copying is expensive, you can try to create a mapping type of < string, Object > First query their maps, and then query the maps you created with local modifications
If you do know that their return type is immutable and you only have it, the @ suppresswarnings ("unchecked") comment is a legitimate way to resolve warnings, but I will carefully examine these assumptions and make extensive comments
To learn about extensions vs super, view it this way Since this value can be any type of extended object, the following is valid
Map<String,Number> strToNum = new HashMap<String,Number>(); strToNum.put("one",Integer.valueOf(1)); // OK Map<String,String> strToStr = new HashMap<String,String>(); strToStr.put("one","1"); // OK Map<String,? extends Object> strToUnk = randomBoolean() ? strToNum : strToStr; strToUnk.put("null",null); // OK. null is an instance of every reference type. strToUnk.put("two",Integer.valueOf(2)); // NOT OK. strToUnk might be a string to string map strToUnk.put("two","2"); // NOT OK. strToUnk might be a string to number map
So put does not apply to extended boundary types But it can work well with reading operations such as get:
Object value = strToUnk.get("one"); // We don't kNow whether value is Integer or String,but it is an object (or null).
If you want the map to use "put" instead of "get", you can use "super" instead of extend, as shown below:
Map<String,Number>(); Map<String,Object> strToObj = new HashMap<String,Object>(); Map<String,? super Number> strToNumBase; if (randomBoolean()) { strToNumBase = strToNum; } else { strToNumBase = strToObj; } // OK. We kNow that any subclass of Number can be used as values. strToNumBase.put("two",Double.valueOf(2.0d)); // But Now,gets don't work as well. Number n = strToNumBase.get("one"); // NOT OK.