克服Java中的类型擦除



我有一个无法更改的客户端类。

List<Integer> list1= Arrays.asList(1,2,3);
System.out.println("Total sum is:"+sum(list1));
printlist(list1);
List<Double> list2=Arrays.asList(1.0,2.0,3.0);
System.out.println("Total sum is:"+sum(list2));
printlist(list2);

我这里有商业逻辑

private static Object sum(List<? extends Number> list) {
double sum = 0;
for (Number i: list) {
sum+=i.doubleValue();
}     
return sum;
}

所以我想返回6表示整数,返回6.0表示双精度。我该怎么做?我想根据类型将sum类型转换为int或double,但由于类型擦除,所有信息都丢失了。有人能帮我吗?

列表中的对象在运行时仍然具有与其关联的类型信息。唯一被擦除的类型是泛型的类型(即您的示例中的List(。泛型在编译时进行检查,但不在生成的字节码中进行维护。这意味着您可以使用instanceof检查集合的内容

private static Object sum(List<? extends Number> list) {
Integer integerSum = 0;
Double doubleSum = 0.0;
boolean hasDouble = false;
for (Number i: list) {
if (i instanceof Integer) {
integerSum += i.intValue();
} else {
doubleSum += i.doubleValue();
hasDouble = true;
}
}
if (hasDouble)
return doubleSum + integerSum;
return integerSum;
}

该代码在处理混合列表时具有一些特性,并且不能正确处理LongShortByte等。

使用"instanceof">

if( i instanceof Double) {
System.out.println("param is a Double");
}
else if( i instanceof Integer) {
System.out.println("param is an Integer");
}

假设Number子类实例可以用double表示是危险的。为了安全地执行此操作,您需要检查所有可能的类型。

@SuppressWarnings("unchecked")
private static <T extends Number> T sum(List<T> list) {
Objects.requireNonNull(list);
if (list.isEmpty() || list.contains(null))
throw new IllegalArgumentException();
Class<T> clazz = (Class<T>) list.get(0).getClass();
if (clazz == Integer.class) {
return (T) (Integer) list.stream().mapToInt(i -> (Integer) i).sum();
}
else if (clazz == Double.class) {
return (T) (Double) list.stream().mapToDouble(i -> (Double) i).sum();
}
/* And other Number subclass types */
// Not possible if all types covered
throw new IllegalStateException();
}

以下是与此相关的问题/答案。

最新更新