有没有办法避免构造函数传递类?

时间:2011-04-03 03:15:53

标签: java generics

考虑这个HashMap扩展(如果它为null,则在调用“get”时生成V类的实例)

public class HashMapSafe<K, V> extends HashMap<K, V> implements Map<K, V>{

    private Class<V> dataType;

    public HashMapSafe(Class<V> clazz){
        dataType = clazz;
    }
    @SuppressWarnings("unchecked")
    @Override
    public V get(Object key) {
        if(!containsKey(key)){
            try {
                put((K)key, dataType.newInstance());
            } catch (InstantiationException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return super.get(key);
    }
}

使用它是这样的

Map<String,Section> sections = new HashMapSafe<String,Section>(Section.class);
sections.get(sectionName); //always returns a Section instance, existing or new

在我看来,两次提供“部分”一次多余,一次作为通用类型,并且还提供它的类。我认为这是不可能的,但是有没有实现HashMapSafe,(保持相同的功能)所以它可以像这样使用?

Map<String,Section> sections = new HashMapSafe<String,Section>();

或者像这样?:

Map<String,Section> sections = new HashMapSafe<String>(Section.class);

5 个答案:

答案 0 :(得分:6)

由于类型擦除,你无法改进构造函数的使用,正如其他人已经指出的那样,但你应该能够通过使用静态工厂方法而不是构造函数来提高详细程度......

我不在编译器前面,我在第一次尝试时永远无法获得方法类型参数,但它会像这样......

public static <K,V> Map<K,V> create( Class<V> cl )
{
    return new HashMapSafe<K,V>(cl);
}

...

Map<String,Section> sections = HashMapSafe.create(Section.class);

答案 1 :(得分:3)

不,没有。 Java没有Reified generics

然而,

GuavaMapMaker#makeComputingMap()

的风格方面有一个很好的解决方案
Map<String, Integer> numbers = new MapMaker().makeComputingMap(new Function<String, Integer>() {
    public Integer apply(String key) {
        return 0;
    }
});

当密钥不存在时,设置并返回0而不是null(并且它是线程安全的,而不是您的解决方案)。

答案 2 :(得分:1)

两者都不可能。第一个要求能够做new V()这样的事情,而这是不可能完成的。第二个需要能够在运行时设置V类型,因为它在构造函数中传递,这也是无法完成的。请记住,泛型只用于编译时,它们会在运行时被删除。

答案 3 :(得分:1)

我发现这篇文章很有趣:Reflecting generics

简而言之:

  public abstract class AbstractUserType<T> implements UserType {
    ...
    public Class returnedClass {
      ParameterizedType parameterizedType =
        (ParameterizedType) getClass().getGenericSuperClass();
     return (Class) parameterizedtype.getActualTypeArguments()[0];
    }
    ...
  } 

答案 4 :(得分:0)

  

有没有办法避免构造函数传递Class?

简而言之,没有。

根本原因是“类型擦除”。在运行时,HashMapSafe的实现没有隐含的与类型参数对应的类型的知识。该信息已删除。如果您需要实现知道类型是什么,则需要将其作为与Class兼容的Class<V>对象传递。

Map<String,Section> sections = new HashMapSafe<String,Section>();

由于类型擦除,这不起作用;见上文。

Map<String,Section> sections = new HashMapSafe<String>(Section.class);

这不起作用,因为Java语言要求您在使用该语法时为所有类型参数指定类型(或通配符)。