Java Generics: Infer and reference a type used in the class instantiation
Given a KeyHolder interface such as the following:
public interface KeyHolder<K extends Key> {
K getKey();
}
I'd like to create a class like this:
public KeyHolderSet<H extends KeyHolder<K extends Key>> extends HashSet<H> {
public Set<K> getKeySet() {
Set<K> keySet = new HashSet<K>();
for (H keyHolder : this) {
keySet.add(keyHolder.getKey());
}
return keySet;
}
}
But that doesn't work, the closest I can get is this:
public KeyHolderSet<H extends KeyHolder<? extends Key>> extends HashSet<H> {
public <K extends Key> Set<K> getKeySet() {
Set<K> keySet = new HashSet<K>();
for (H keyHolder : this) {
// Explicit cast to K
keySet.add((K)keyHolder.getKey());
开发者_Python百科 }
return keySet;
}
}
Any way around this?
Assuming the implementation class of the KeyHolder that is stored in the set is not important, you could try something like this:
public class KeyHolderSet<K extends Key> extends HashSet<KeyHolder<K>> {
public Set<K> getKeySet() {
...
}
}
You need to write it like this:
public KeyHolderSet<K extends Key, H extends KeyHolder<K>> extends HashSet<H> {
public Set<K> getKeySet() {
...
}
}
Unfortunately you will have to declare the type of K first and it cannot be inferred.
Maybe
public class KeyHolderSet<K extends Key, H extends KeyHolder<K>> extends
HashSet<H> {
public Set<K> getKeySet() {
...
}
}
if you don't mind parameterizing KeyHolderSet twice.
Given that KeyHolder<K extends Key>
it seems unnecessary to use KeyHolderSet<H extends KeyHolder<K extends Key>>
Just stick with:
public class KeyHolderSet<H extends KeyHolder<?>>
and you should be ok.
Edit: I see your problem with getKeySet()
. This method should return H instead of K. H will be typed with what you entered in the declaration of KeyHolderSet (The variabe, not the class).
public class KeyHolderSet<H extends KeyHolder<?>> extends HashSet<H> {
private H theKeySet;
public void setKeySet(H keyset) {
theKeySet = keyset;
}
public H getKeySet() {
return theKeySet;
}
}
-
class betterKey extends Key {
}
-
public static void main(String[] args) {
KeyHolder<betterKey> kh = new KeyHolder<betterKey>() {
};
KeyHolderSet<KeyHolder<betterKey>> khs = new KeyHolderSet<KeyHolder<betterKey>>();
khs.setKeySet(kh);
KeyHolder<Key> kh2 = khs.getKeySet(); // Type mismatch
}
As you can see khs.getKeySet()
returns KeyHolder<betterKey>
as expected.
Edit2: You can build up the set outside the KeyHolderSet class:
public static void main(String[] args) {
KeyHolderSet<KeyHolder<betterKey>> khs = new KeyHolderSet<KeyHolder<betterKey>>();
Set<betterKey> bks = new HashSet<betterKey>();
for (KeyHolder<betterKey> kh : khs) {
bks.add(kh.getKey());
}
}
One alternate solution i came up with is returning a completely generic Set, remember all type checking will be lost this way.
public class KeyHolderSet<H extends KeyHolder<?>> extends HashSet<H> {
public <K extends Key> Set<K> getKeySet() {
Set<K> s = new HashSet<K>();
for (H keyHolder : this) {
s.add((K) keyHolder.getKey()); // Unchecked cast
}
return s;
}
public static void main(String[] args) {
KeyHolderSet<KeyHolder<betterKey>> khs = new KeyHolderSet<KeyHolder<betterKey>>();
Set<Key> ks = khs.getKeySet(); // No problem
Set<betterKey> bks = khs.getKeySet(); // No problem
Set<evenBetterKey> ss = khs.getKeySet(); // No problem
}
}
class betterKey implements Key {
}
class evenBetterKey extends betterKey {
}
精彩评论