我正在寻找一种使用通用函数优化代码库中某些内容的方法。有一个返回类型为List<Object>
的函数,其返回类型可能为List<SpecifiedType>
。
Bellow是该函数的简化版本,称为function
。它采用参数类型,并基于它调用相应的函数(此处限于String
)或通用函数。
public static ArrayList<String> forString(){
ArrayList<String> res = new ArrayList<>();
// Fetching and processing data specific to String
return res;
}
public static <T> ArrayList<T> forGeneric(Class<T> type){
ArrayList<T> res = new ArrayList<>();
// Fetching data
return res;
}
public static <T> ArrayList<T> function(Class<T> type){
if(type == String.class)
return (ArrayList<T>) forString();
return forGeneric(type);
}
上面的函数的目标是这样调用的:ArrayList<SomeType> someTypes = function(SomeType.class);
关于以上代码,我注意到了两件事:
即使我们知道如果将类型ArrayList<T>
作为参数传递,它也将返回String
,就像ArrayList<String>
方法一样,需要强制转换为forString()
对ArrayList<T>
的发布会发出Unchecked cast
警告,即使返回类型为ArrayList<String>
我的问题是,有什么更好的方法(最好不使用演员表),如果没有,那么为什么
答案 0 :(得分:4)
首先,该语句在逻辑上是错误的
if(type.isInstance(String.class))
如果type
是Class<String>
,则isInstance
正在检查参数是否为字符串实例。您传递的参数是一个类实例(特别是Class<String>
)。
如果您愿意,
String.class.isInstance(String.class) == false
您的意思是
if(type == String.class)
但是,即使此逻辑错误已解决,您的代码仍将具有未经检查的强制转换警告。
您缺少的部分就在这里
即使我们知道,如果键入 字符串作为参数传递,它将仅返回ArrayList<T>
像ArrayList<String>
方法
完全正确。 我们知道这一点。但是我们知道的和编译器知道的是两件事。编译器不够聪明,无法检查条件并意识到类型还可以。可以想象,可以足够聪明,但事实并非如此。
这正是为什么这表现为警告而不是错误的原因。这是一个警告,因为您正在做的事情潜在地错误;它不是绝对错误,否则根本无法编译。在这种情况下,警告应作为提示您再次检查您所做的正确,然后您可以很高兴地将其取消。
forString()
最后-这可能是您所设计的示例的伪像-但所有这些方法都没有用。与直接调用@SuppressWarnings("unchecked")
public static <T> ArrayList<T> function(Class<T> type){
if(type == String.class)
return (ArrayList<T>) forString();
return forGeneric(type);
}
相比,似乎没有任何优势。在运行时,实际实例是相同的,无论它来自3种方法中的哪一种。
答案 1 :(得分:0)
运行时代码无法根据运行时信息返回不同的泛型类型,因为泛型是一种编译时机制。
要真正摆脱编译器警告,我将返回一个新列表:
public static <T> ArrayList<T> function(Class<T> type){
ArrayList<?> result;
if (type.equals(String.class)) {
result = forString();
} else {
result = forGeneric(type);
}
ArrayList<T> typedResult = new ArrayList<>(result.size());
for (Object item : result) {
typedResult.add(type.cast(item));
}
return typedResult;
}
这似乎很浪费,但不是。新列表不是新对象的列表,而是新引用。引用非常小,可能不超过256个字节,因此,包含4,000个对象的列表将占用不超过一兆字节的RAM。