Java generics and bounded types - java

I have a wrapper class for ConcurrentMap like the following:
public MapWrapper<K, V> implements ConcurrentMap<K, V> {
private final ConcurrentMap<K, V> wrappedMap;
...
#Override
public void putAll(Map<? extends K, ? extends V> map) {
wrappedMap.putAll(map); // <--- Gives compilation error
}
...
}
The marked line triggers the following compilation error:
method putAll in interface java.util.Map<K,V> cannot be applied to given types;
required: java.util.Map<? extends capture#5 of ? extends K,? extends capture#6 of ?
extends V>
found: java.util.Map<capture#7 of ? extends K,capture#8 of ? extends V>
reason: actual argument java.util.Map<capture#7 of ? extends K,capture#8 of ? extends V>
cannot be converted to java.util.Map<? extends capture#5 of ? extends K,? extends
capture#6 of ? extends V> by method invocation conversion
I suspect the unbounded wildcards are the culprit but I can't change the method signature since it is inherited from the ConcurrentMap interface. Any ideas?

Have you seen:
What is the difference between bounded wildcard and type parameters?

Let's look to signature of putAll
public void putAll(Map<? extends K, ? extends V> m)
... and to error which you got:
cannot be converted to java.util.Map<? extends capture#5 of ? extends K,? extends
So reason why you can't do it, it's restriction of merging of inheritance tree in Java.
Probably, will be better to write your own implementation of putAll method.
Thanks, hope it will help you.

Related

why iterating a received generic HashMap can only be done with enhanced for-loop?

I am implementing a putAll() method.
I tried to iterate the map using entrySet and iterator methods, but received a compiling error that m.entrySet().iterator() return value could not be converted to Iterator<Entry<? extends K, ? extends V>>.
why? if the map is of that type, it's iterator should be as well, no?
thank you!
doesn't compile:
#Override
public void putAll(Map<? extends K, ? extends V> m) {
Iterator<Entry<? extends K, ? extends V>> iter = m.entrySet().iterator();
while (iter.hasNext()) {
Entry<? extends K, ? extends V> entry = iter.next();
put(entry.getKey(), entry.getValue());
}
}
compiles and works fine:
#Override
public void putAll(Map<? extends K, ? extends V> m) {
Objects.requireNonNull(m, "putAll(): argument is null");
for (Entry<? extends K, ? extends V> entry : m.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
Change
Iterator<Entry<? extends K, ? extends V>> iter
To
Iterator<? extends Entry<? extends K, ? extends V>> iter
Think about it this way, each time the method is called, m, which has type Map<? extends K, ? extends V>, points to an object with a "real" type of Map<some actual subtype of K we don't know, some actual subtype of V we don't know>. (These unknown types might be different in each call of the method, but in each call, the passed object must have some specific type for each of the type parameters, though we don't know it.)
Therefore, m.entrySet().iterator() has type Iterator<Map.Entry<some unknown subtype of K, some unknown subtype of V>>. This is not a subtype of Iterator<Map.Entry<? extends K, ? extends V>>, because when the top-level type argument is not a wildcard, the top-level type arguments must match exactly, and they don't here.
Iterator<Map.Entry<some unknown subtype of K, some unknown subtype of V>> is not a subtype of Iterator<Map.Entry<? extends K, ? extends V>> even though Map.Entry<some unknown subtype of K, some unknown subtype of V> is a subtype of Map.Entry<? extends K, ? extends V>, just like how List<String> is not a subtype of List<Object>, even though String is a subtype of Object.
One solution is to add a wildcard at the top level, like in Lino's answer: Iterator<? extends Map.Entry<? extends K, ? extends V>>.

Extension of generic Java class does not recognize super constructor

Can someone please help me understand why this Java code doesn't compile?
The idea is that A is a tree-like class for a type T that takes a collection of children at construction.
Then I define an extension B of A that specializes T for Pair<R,R>.
class A<T> {
A(T t, Collection<? extends A<? extends T>> cOfAs) {
}
}
class B<R> extends A<Pair<R,R>> { // Pair is just a POJO class
B(Pair<R,R> pair, Collection<? extends B<? extends R>> cOfBs) {
super(pair, cOfBs);
// ERROR: The constructor A<Pair<R,R>>(Pair<R,R>, Collection<capture#1-of ? extends B<? extends R>>) is undefined
}
}
The type of the second parameter doesn't match. The B constructor takes Collection<? extends B<? extends R>>, but the superclass constructor takes a Collection<? extends A<? extends T>>.
You've defined T to be Pair<R, R> in your B class, so instead of R, use Pair<R, R>. Also the ? extends part must match, so change ? extends B<...> to ? extends A<...>. The signature of B's constructor now looks like this:
B(Pair<R,R> pair, Collection<? extends A<? extends Pair<R, R>>> cOfBs)
It must be ? extends A exactly, because ? extends B may not match ? extends A. The only way to get this to match is to introduce another type parameter in A representing the "self" type, and to use it in the second parameter of the constructor.
class A<T, S extends A<T, S>> {
A(T t, Collection<? extends S> cOfAs) {
}
}
Then in B, supply B<R> as "self".
class B<R> extends A<Pair<R,R>, B<R>> { // Pair is just a POJO class
B(Pair<R,R> pair, Collection<? extends B<R>> cOfBs) {
super(pair, cOfBs);
}
}
The type of second argument of constructor is wrong:
Error:(20, 25) java: incompatible types: java.util.Collection<capture#1 of ? extends Main.B<? extends R>> cannot be converted to java.util.Collection<? extends Main.A<? extends javafx.util.Pair<R,R>>>
To fix it change second argument to Collection<? extends B<R>> cOfBs

Java infinitely recursive self referential types

I'm trying to create an implementation of Map that takes collections as keys.
What do you even call this conundrum?
What is the right way to do the class signature?
class SubClass <K extends Collection<E>, V> implements Map<K, V>
^^ Is improper syntax, but indicates what I want to do.
class SubClass <K extends Collection<K>, V> implements Map<Collection<K>, V>
^^ Results in a SubClass for which you can never declare the generic type. K is infinitely recursive. It also doesn't describe the type of behavior I'm looking for.
class SubClass <K , V> implements Map<K, V>
^^ Doesn't enforce the constraint that K needs to be a Collection
class SubClass <K extends Collection, V> implements Map<K, V>
^^ Doesn't allow us to know the generic types of the Collection
class SubClass <E, K extends Collection<E>, V> implements Map<K, V>
^^ Works, but is rather unwieldy
You'll need a type parameter for the Collection element type, potentially a type parameter for the actual Collection type if you need it, and a type parameter for the values.
class SubClass<E, K extends Collection<E>, V> implements Map<K, V> { ... }
If you don't need the specific Collection type, you can use
class SubClass<E, V> implements Map<Collection<E>, V> { ... }
Concerning the various comments on your question
public class Example {
public static void main(String[] args) throws Exception {
Whatever<Self> s = new Whatever<>();
}
}
class Self extends ArrayList<Self> {
}
class Whatever<E extends Collection<E>> {
}

Java Generic Types and Entry

I am trying to implement a generic DDLinkedList of Entries. I have the following classes defined.
class DoublyLinkedList<T extends Comparable<T>>
class DLLNode<T extends Comparable<T>>
Entry<K extends Comparable<K>, V> implements Comparable<Entry<K, V>>
Once I try to create an array of DoublyLinkedlist of type Entry as below:
DoublyLinkedList<DLLNode<Entry<K, V>>> array[] = (DoublyLinkedList<DLLNode<Entry<K, V>>>[]) new DoublyLinkedList[TABLE_SIZE];
I get an error message:
"The type DLLNode<Entry<K,V>> is not a valid substitute for the bounded
parameter <T extends Comparable<T>> of the type DoublyLinkedList<T>"
From my other standing I thought I could make a Generic Type T of Entry.
My question:
Am I going about the wrong way of doing this or am I implementing it wrong?
Your definition for DoublyLinkedList says that it must take a type which is comparable with itself. But your definition for DLLNode does not implement Comparable<DLLNode<T>> which means that DLLNode is not comparable with its own type. So you can't use DLLNode as a parameter type in DoublyLinkedList.
DLLNode needs to actually implement Comparable and not use it as its generic type.
Also your syntax is way off. Arrays cannot use generics. The best you can do is this:
DoublyLinkedList<?> array[] = new DoublyLinkedList[TABLE_SIZE];
You need to do:
class DoublyLinkedList<T extends Comparable<? super T>> {}
class DLLNode<T extends Comparable<? super T>> implements Comparable<DLLNode<T>> {
public int compareTo(DLLNode<T> other) {
return 0;
}
}
abstract class Entry<K extends Comparable<? super K>, V> implements Comparable<Entry<K, V>> {}
class HashEntry<K extends Comparable<? super K>, V> extends Entry<K, V> {
public int compareTo(Entry<K, V> other) {
return 0;
}
}
Then wherever you decide to use this:
DoublyLinkedList<DLLNode<HashEntry<K, V>>> array[] = new DoublyLinkedList[TABLE_SIZE];
The reason why this works is because of that <? super T> declared for the DLLNode class. If you just have <T>, this will not work because HashEntry will not be comparable. Generics in Java is a bit of a pain to get right.

JDK7 generics not compiling

The following code compiles in jdk6 but not in jdk7. Please suggest any workarounds
public interface LocalCacheMap<K extends Comparable<? super K>, V>
extends ClearableCache<K>, Iterable<V>{
V get(K key);
}
public class Universe<K extends Comparable<? super K>, V, TSKEY extends Comparable<? super TSKEY>> extends MasterLocalCache<K>
implements Iterable<V>, LocalCacheMap<K, V>, TsDaoInfo<TSKEY, K>, ValueConverter<K, Object, V>{
public V get(K key) {
return get(key, keyFunct);
}
abstract public TSKEY buildTsKey(K key, Date date);
abstract public K getObjKey(TSKEY tsKey);
abstract public Date getDateKey(TSKEY tsKey);
}
public class JdbcTimesSeriesCacheDef<K extends Comparable<? super K>, TSKEY extends Comparable<? super TSKEY>, LC extends Universe<K,?,TSKEY>&DataSourceProvider, T> extends AbstractRawTimeSeriesCacheDef<K, T, LC> {
private final SqlDefs<T> defs;
}
When compiling with jdk7, I am getting the following error
JdbcTimesSeriesCacheDef error: get(K#1) in Universe cannot implement get(K#2) in LocalCacheMap
Change
LC extends Universe<K,?,TSKEY>&DataSourceProvider,
to
LC extends Universe<K,T,TSKEY>&DataSourceProvider,
I solved this by using specific Value type 'V' in place of "?"
public class JdbcTimesSeriesCacheDef, V, TSKEY extends Comparable, LC extends Universe&DataSourceProvider, T> extends AbstractRawTimeSeriesCacheDef {
private final SqlDefs defs;
}

Categories

Resources