Dav*_*vis 5 java generics instantiation hashmap map
现有系统HashMap
通过其Generics
类创建了大量实例:
import java.util.Map;
import java.util.HashMap;
public class Generics {
public static <K,V> Map<K, V> newMap() {
return new HashMap<K,V>();
}
public static void main( String args[] ) {
Map<String, String> map = newMap();
}
}
Run Code Online (Sandbox Code Playgroud)
这是实现Map
接口的所有类实例的单点创建.我们希望能够在不重新编译应用程序的情况下更改地图实现.这将允许我们使用Trove THashMap
,例如,优化应用程序.
THashMap
由于许可条件,该软件无法与Trove捆绑在一起.因此,如果有一种方法可以指定要在运行时实例化的地图名称(对于那些没有此类许可限制的人),那将会很棒.例如:
import java.util.Map;
import java.util.HashMap;
import gnu.trove.map.hash.THashMap;
public class Generics {
private String mapClassName = "java.util.HashMap";
@SuppressWarnings("unchecked")
public <K,V> Map<K,V> newMap() {
Map<K,V> map;
try {
Class<? extends Map<K,V>> c = (Class<Map<K,V>>)Class.forName(
getMapClassName() ).asSubclass( Map.class );
map = c.newInstance();
}
catch( Exception e ) {
map = new HashMap<K,V>();
}
return map;
}
protected String getMapClassName() {
return this.mapClassName;
}
protected void setMapClassName( String s ) {
this.mapClassName = s;
}
public static void main( String args[] ) {
Generics g = new Generics();
Map<String, String> map = g.newMap();
System.out.printf( "Class = %s\n", map.getClass().toString() );
g.setMapClassName( "gnu.trove.map.hash.THashMap" );
map = g.newMap();
System.out.printf( "Class = %s\n", map.getClass().toString() );
}
}
Run Code Online (Sandbox Code Playgroud)
有没有办法@SupressWarnings
在编译时避免注释-Xlint
并仍然避免警告?
@SuppressWarnings
有没有办法在编译时避免注释-Xlint
并仍然避免警告?
编号Class.forName
返回一个Class<?>
. 分配它的唯一方法Class<? extends Map<K, V>>
是进行未经检查的强制转换。有时未经检查的强制转换是必要的,因此@SuppressWarnings("unchecked")
这里使用是可以接受的(前提是您很好地记录了原因)。
Class<? extends Map<?, ?>>
恕我直言,保留对 to 的引用然后对newInstance
to的结果进行未经检查的转换会更正确Map<K,V>
。我这么说只是因为Class
对象是原始类型的规范表示,因此像这样的类型Class<? extends Map<K, V>>
有点误导。
这超出了问题的范围,但这里为您的解决方案提供了建议的替代方案:
public interface MapFactory {
<K, V> Map<K, V> newMap() throws Exception;
}
public enum HashMapFactory implements MapFactory {
INSTANCE;
@Override
public <K, V> Map<K, V> newMap() {
return new HashMap<K, V>();
}
}
public static final class DynamicMapFactory implements MapFactory {
private final Constructor<? extends Map<?, ?>> constructor;
private DynamicMapFactory(Constructor<? extends Map<?, ?>> constructor) {
this.constructor = constructor;
}
@Override
//Impl note: these checked exceptions could also be wrapped in RuntimeException
public <K, V> Map<K, V> newMap() throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
@SuppressWarnings("unchecked") //this is okay because the default ctor will return an empty map
final Map<K, V> withNarrowedTypes = (Map<K, V>)constructor.newInstance();
return withNarrowedTypes;
}
public static DynamicMapFactory make(String className) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
@SuppressWarnings("unchecked") //Class<? extends Map> can safely be cast to Class<? extends Map<?, ?>>
final Class<? extends Map<?, ?>> type =
(Class<? extends Map<?, ?>>)Class.forName(className).asSubclass(Map.class);
final Constructor<? extends Map<?, ?>> constructor = type.getDeclaredConstructor();
return new DynamicMapFactory(constructor);
}
}
public static void main(String[] args) throws Exception {
Map<String, Integer> map1 = HashMapFactory.INSTANCE.newMap();
Map<String, Integer> map2 = DynamicMapFactory.make("java.util.TreeMap").newMap();
System.out.println(map1.getClass()); //class java.util.HashMap
System.out.println(map2.getClass()); //class java.util.TreeMap
}
Run Code Online (Sandbox Code Playgroud)