开发者

Java Generics: Infer and reference a type used in the class instantiation

开发者 https://www.devze.com 2023-03-11 02:58 出处:网络
Given a KeyHolder interface such as the following: public interface KeyHolder<K extends Key> { K getKey();

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 {
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号