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>> {
}
Related
I am reading the java docs on generics, specifically this page on bounded types and am lost. Here is a simple version of my code, for context I generically want a compare-able key, one with an Integer and another abstract class with a Date, here is just the base abstract class and the integer implementation:
Abstract class:
public abstract class A<K extends Comparable<K>, V> extends TreeMap<K, V>
Integer Abstract class:
public abstract class B<K extends Integer, V> extends A<K,V>
The error I get is in the type reference of the second class at the part extends A<K,V>. Specifically, my IDE is underlying the K and says Type parameter 'K' is not within its bound; should implement 'java.lang.Comparable<K>'
I am confused on this because in the definition of Integer, it implements a Comparable<Integer>, is that not enough to satisfy this? Moreover, when I try to do the following, public abstract class B<K extends Integer & Comparable<K>, V> extends A<K,V>, that does not work either.
Am I misunderstanding something with generics?
Since Integer is a final class, the correct definition of B would be:
public abstract class B<V> extends A<Integer,V> {
}
You don't need the K type parameter.
The compiler error occurs because although Date implements Comparable<Date>, a subclass of Date might not implement Comparable<SubclassOfDate>, so the compiler complains.
You can fix this by changing A's declaration to use a wildcard:
public abstract class A<K extends Comparable<? super K>, V> extends TreeMap<K, V>
However, you probably intended to declare B like this:
public abstract class B<V> extends A<Integer,V> {
}
Integer is final, no other class can inherit it. So B does not have to be generic on K.
As for the class with Date as the key, you probably want to do it like this as well:
public abstract class C<V> extends A<Date,V> {
}
But since Date is not final, you could make a generic parameter K extends Date:
public abstract class C<K extends Date, V> extends A<K,V> {
}
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.
What is the meaning of
class MyMap<K, V> implements Map<Comparable<K>, V>
in class definition? I don't understand how MyMap<K, V> can be a valid implementation of Map<Comparable<K>, V> as MyMap needs K and V whereas Map needs Comparable<K> and V
You're over-analyzing the declaration. K is just any type, and MyMap implements Map<Comparable<K>, V>.
[...] don't understand how MyMap<K, V> can be a valid implementation of Map<Comparable<K>, V> [...]
It can if you implement the methods required by Map<Comparable<K>, V>. In particular MyMap needs to implement a method with the following signature for instance:
public Set<Comparable<K>> keySet() {
...
}
Note that the above method declaration puts no constraint on K. In other words the class declaration should not be confused with
class MyMap<K extends Comparable, V> implements Map<K, V>
which means that K needs to be Comparable.
I tried to add interface Comparable to class SimpleEntry by subclass it. Because SimpleEntry is a generic type, I used this:
public class SimpleEntryComparable<K, V> extends SimpleEntry<K, V> implements
Comparable<T> {
public SimpleEntryComparable(K arg0, V arg1) {
super(arg0, arg1);
// TODO Auto-generated constructor stub
}
}
And eclipse complained "T cannot be resolved to a type".
I'm confused about subclass a generic class and add interfaces... anyone can tell me something about this?
chrylis' answer is correct. Below it I see you have this comment:
But in compareTo(), I want to "return o.getKey() - this.getKey();"
Based on this comment, it sounds like you want the following:
public class SimpleEntryComparable<K extends Comparable<? super K>, V>
extends SimpleEntry<K, V>
implements Comparable<SimpleEntryComparable<K, V>> {
#Override
public int compareTo(final SimpleEntryComparable<K, V> other) {
return getKey().compareTo(other.getKey());
}
}
This ensures that K is comparable to itself (or some super-type of itself), so that your code can delegate to that type's compareTo implementation. This is the only way to do generic comparisons of reference types - as chrylis points out, arithmetic operations are only supported for primitives.
The <T> on Comparable tells the compiler what type the class can be compared to. In your case, if you want to be able to compare to other SimpleEntryComparables, you just need implements Comparable<SimpleEntryComparable<K,V>> (and compareTo, of course!).
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.