Java 如何对具有不同类的类似方法使用泛型
有没有办法使用一些通用方法来统一下面类似的方法Java 如何对具有不同类的类似方法使用泛型,java,generics,Java,Generics,有没有办法使用一些通用方法来统一下面类似的方法 public ClassA getInstanceA(String key) { if (instanceAMap.contains(key)) { return instanceAMap.get(key); } ClassA result = new ClassA(); instanceAMap.put(key, result); return result; } public ClassB g
public ClassA getInstanceA(String key)
{
if (instanceAMap.contains(key))
{
return instanceAMap.get(key);
}
ClassA result = new ClassA();
instanceAMap.put(key, result);
return result;
}
public ClassB getInstanceB(String key)
{
if (instanceBMap.contains(key))
{
return instanceBMap.get(key);
}
ClassB result = new ClassB();
instanceBMap.put(key, result);
return result;
}
public ClassC getInstanceC(String key)
{
if (instanceCMap.contains(key))
{
return instanceCMap.get(key);
}
ClassC result = new ClassC();
instanceCMap.put(key, result);
return result;
}
所以,我希望所有类只有一个方法。
在C++中,它可以被封装成宏,但是它如何在java中优雅地完成。< p>因为泛型类型的类型删除,在运行时不能创建泛型类型的新实例。 如果您使用的是Java8,那么您可以让方法获取一个供应商,该供应商为您提供一个新对象。这使得调用方有责任创建对象。您可以这样做:
Map<String, Object> map = new HashMap<>();
public <T> T getInstance(String key, Supplier<T> objectSupplier) {
if (instanceAMap.containsKey(key)) {
return (T) map.get(key);
}
T result = objectSupplier.get();
map.put(key, result);
return result;
}
由于未经检查的强制转换,以后不要执行此操作:
Integer i = getInstance("String", () -> 5);
它将导致ClassCastException
编辑:这是一个为每种类型创建新地图的版本
Map<Class<?>, Map<String, ?>> maps = new HashMap<>();
public <T> T getInstance(String key, Class<T> type, Supplier<T> objectSupplier) {
Map<String, T> map;
if (maps.containsKey(type)) {
map = (Map<String, T>) maps.get(type);
} else {
map = new HashMap<>();
maps.put(type, map);
}
if (map.containsKey(key)) {
return map.get(key);
}
T result = objectSupplier.get();
map.put(key, result);
return result;
}
Map>maps=newhashmap();
public T getInstance(字符串键、类类型、供应商对象供应商){
地图;
if(地图容器(类型)){
map=(map)maps.get(type);
}否则{
map=新的HashMap();
地图。放置(类型,地图);
}
if(地图容器(图例)){
返回map.get(key);
}
T result=objectSupplier.get();
地图。放置(键、结果);
返回结果;
}
单一方法解决方案需要传入类型:
private Map<Class<?>, Map<String, Object>> instanceMaps;
public <T> T getInstance(String key,
Class<T> instanceType) {
if (instanceMaps == null) {
instanceMaps = new HashMap<>();
instanceMaps.put(ClassA.class, instanceAMap);
instanceMaps.put(ClassB.class, instanceBMap);
instanceMaps.put(ClassC.class, instanceCMap);
}
Map<String, Object> instanceMap = instanceMaps.get(instanceType);
if (instanceMap == null) {
throw new IllegalArgumentException("Unknown type: " + instanceType);
}
Object value = instanceMap.get(key);
if (value == null) {
try {
instanceMap.put(key, value = instanceType.newInstance());
} catch (ReflectiveOperationException e) {
throw new IllegalArgumentException(e);
}
}
return instanceType.cast(value);
}
private MAPI是否确定所有这些类都有一个可访问的无参数构造函数?您的类为什么拥有3个不同的映射?你能重构它并拥有一个映射吗?@Seelenvirtuose不,类可能有任何构造函数,这只是一个例子。@user902383类的键可能不是唯一的。不幸的是,这些方法中的每一个都在另一个映射上操作。这也必须解决。哦,我没看到。我想我们也需要映射作为参数。此外,在Java-8之前的版本中,您可以使用类型标记:T getInstance(字符串键,类类型)
。方法实现还可以使用此类型生成实例:type.newInstance()
。不,可以在方法所属的实例中维护映射。使用类型标记(见上文),您还可以获得正确的映射。如果您相应地更新了您的问题,我将删除我的下一票。@请参见LenVirtuose如何使用类型标记检索正确的映射?在第一个示例中,使用值类型为Object
的instanceMap会丢失类型信息。在上一个示例中,您使用instanceType.cast(value)
来转换值。这并不比使用(T)值来强制转换值更安全。您将丢失编译器警告,但它仍然可以抛出ClassCastException。重载的例子看起来不错。@marstran是的,如果没有方法重载,一些强制转换是不可避免的。但这样,就没有什么意外了:ClassCastException发生在一个明显的地方,如果它发生的话。另一方面,当您执行未经检查的强制转换时,您会在代码的后面的意外位置得到ClassCastException。例如,将一个包含整数的原始列表强制转换为List
,将在稍后迭代或调用get(int)时导致意外异常。
private Map<Class<?>, Map<String, Object>> instanceMaps;
public <T> T getInstance(String key,
Class<T> instanceType) {
if (instanceMaps == null) {
instanceMaps = new HashMap<>();
instanceMaps.put(ClassA.class, instanceAMap);
instanceMaps.put(ClassB.class, instanceBMap);
instanceMaps.put(ClassC.class, instanceCMap);
}
Map<String, Object> instanceMap = instanceMaps.get(instanceType);
if (instanceMap == null) {
throw new IllegalArgumentException("Unknown type: " + instanceType);
}
Object value = instanceMap.get(key);
if (value == null) {
try {
instanceMap.put(key, value = instanceType.newInstance());
} catch (ReflectiveOperationException e) {
throw new IllegalArgumentException(e);
}
}
return instanceType.cast(value);
}
private <T> T getInstance(String key,
Map<String, T> instanceMap,
Supplier<T> constructor) {
return instanceMap.computeIfAbsent(key, k -> constructor.get());
}
public ClassA getInstanceA(String key) {
return getInstance(key, instanceAMap, ClassA::new);
}
public ClassB getInstanceB(String key) {
return getInstance(key, instanceBMap, ClassB::new);
}
public ClassC getInstanceC(String key) {
return getInstance(key, instanceCMap, ClassC::new);
}
private <T> T getInstance(String key,
Map<String, T> instanceMap,
Class<T> instanceType) {
T value = instanceMap.get(key);
if (value == null) {
try {
instanceMap.put(key, value = instanceType.newInstance());
} catch (ReflectiveOperationException e) {
throw new IllegalArgumentException(e);
}
}
return value;
}
public ClassA getInstanceA(String key) {
return getInstance(key, instanceAMap, ClassA.class);
}
public ClassB getInstanceB(String key) {
return getInstance(key, instanceBMap, ClassB.class);
}
public ClassC getInstanceC(String key) {
return getInstance(key, instanceCMap, ClassC.class);
}
public <T> T getInstance(String key,
Class<T> instanceType) {
Object value = instanceMap.get(key);
if (value != null) {
return instanceType.cast(value);
}
try {
T newValue = instanceType.newInstance();
instanceMap.put(key, newValue);
return newValue;
} catch (ReflectiveOperationException e) {
throw new IllegalArgumentException(e);
}
}