2
public class AutoKeyMap<K,V> {

    public interface KeyGenerator<K> {
        public K generate();
    }    
    private KeyGenerator<K> generator;

    public AutoKeyMap(Class<K> keyType) {
        // WARNING: Unchecked cast from AutoKeyMap.IntKeyGen to AutoKeyMap.KeyGenerator<K>
        if (keyType == Integer.class) generator = (KeyGenerator<K>) new IntKeyGen();
        else throw new RuntimeException("Cannot generate keys for " + keyType);
    }

    public void put(V value) {
        K key = generator.generate();
        ...
    }


    private static class IntKeyGen implements KeyGenerator<Integer> {

        private final AtomicInteger ai = new AtomicInteger(1);

        @Override public Integer generate() {
            return ai.getAndIncrement();
        }

    }


}

在上面的代码示例中,防止给定警告的正确方法是什么,而不添加 a @SuppressWarnings(如果有)?

4

1 回答 1

0

您可以通过执行以下操作临时修复您的代码:

private KeyGenerator<?> generator;

public AutoKeyMap(Class<?> keyType) {
    // WARNING: Unchecked cast from AutoKeyMap.IntKeyGen to AutoKeyMap.KeyGenerator<K>
    if (keyType == Integer.class) generator = new IntKeyGen();
    else throw new RuntimeException("Cannot generate keys for " + keyType);
}

但是如果你需要实现一个AutoKeyMap类似的方法

K generate(){
  return generator.generate();
}

然后它会再次破裂。问题是,一旦您开始对类类型进行运行时检查(就像您在 中所做的那样if(keyType == Integer.class)),Java 编译器就无法静态地确保该类型是正确的。因为你可以实例化new AutoKeyMap<Boolean>(Class<Boolean> keyType)然后写

if(keyType == Boolean.class){
  generator = new IntKeyGen();
}

这显然会中断,因此静态检查的泛型类型的全部意义将丢失。

通常,像您这样涉及动态类型转换的所有问题都超出了泛型,因此您必须忍受未经检查的转换,并确保您编写了足够的单元测试并确保您的代码可以正常工作并且不会ClassCastException在所有情况下都抛出。

于 2010-12-28T15:01:11.457 回答