Java Generics Help: cannot use "Object" as an argument to "? 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)};
    }
}

The code fails to compile when I call valueMapPart1.putand valueMapPart2.put, with an error:

The method put (String, capture # 5-of? Extends Object) in the type Map is not applicable for the arguments (String, Object)

I read on the Internet about generics and wildcards, but I still don't understand what is going wrong. I understand that a value Mapcan be any class that extends Object, which I think may be redundant, since all classes extend Object. And I can’t change generics to something like ? super Object, because it is Mapprovided by some library.

? , valueMap Map<String,Object>, " ".

!

+3
3

extends, put. , , . , <String, Object>, , .

, , @SuppressWarnings("unchecked") , .

extends vs super, . , Object, .

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

, put extends. , get:

Object value = strToUnk.get("one");  // We don't know whether value is Integer or String, but it is an object (or null).

, "put" "get", "super" , :

Map<String, Number> strToNum = new HashMap<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. 
+4

, , .. ? extends Number, . .

.

public void method(List<Number> list) {
}

:

method(new List<Double>()); // <-- Java compiler complains about this
method(new List<Number>()); // <-- Java compiler is happy with this.

List Number Number, List Double, Double Number.

widecard , java-, Number.

public void method(List<? extends Number> list) {
}

:

method(new List<Double>()); // <-- Java compiler is happy with this.
method(new List<Number>()); // <-- Java compiler is happy with this.

, .

public void method(List<? extends Number> list) {
    list.add(new Double()); // this is not allowed
}

" Number", List, List, List .. Double , , . , method

method(new ArrayList<Integer>());

...
public void method(List<? extends Number> list) {
    // adding Double to Integer list does not make sense.
    list.add(new Double()); // compiler error
}

,

private Map<String, Object> origValueMap;

...

Map<String, Object> valueMapPart1 = origValueMap;
valueMapPart1.put(nameMappings[3], new Double(splitAtQuantity));

: new Double(splitAtQuantity) -, Number Object.

+3

- . , " " " ", . - ( ). , , .

Collection<?> Collection<Object> ( Double), Collection<Integer> ( ).

0

Source: https://habr.com/ru/post/1782392/


All Articles