避免涉及运行时传递类的一般情况的不安全强制转换

时间:2010-12-28 13:08:20

标签: java generics casting unchecked-conversion

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();
        }

    }


}

在上面的代码示例中,如果没有添加@SuppressWarnings,阻止给定警告的正确方法是什么?

1 个答案:

答案 0 :(得分: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在所有情况下。