简体   繁体   English

克服Java中的类型擦除

[英]Overcome type erasure in Java

I have a client class which I cannot change. 我有一个不能更改的客户班。

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);

I have the business logic here 我这里有业务逻辑

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

So I want to return 6 for integer and 6.0 for a double. 所以我想为整数返回6,为双精度返回6.0。 How can I do that? 我怎样才能做到这一点? I am thinking to typecast sum as int or double based on type but due to type erasure all the info is lost. 我想根据类型将求和类型转换为int或double,但是由于类型擦除,所有信息都丢失了。 Can someone help me? 有人能帮我吗?

The objects in the list still have type information associated to them at run time. 列表中的对象在运行时仍具有与它们关联的类型信息。 The only erased types are those of the generics (ie List in your example). 唯一擦除的类型是泛型的类型(即示例中的List )。 The generics are checked at compile time, but are not maintained in the generated bytecode. 泛型在编译时检查,但不保留在生成的字节码中。 That means you can use instanceof to check the contents of the collection: 这意味着您可以使用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;
}

The code has some peculiarities to handle mixed lists, and doesn't handle Long , Short , Byte etc. properly. 该代码具有处理混合列表的一些特性,并且不能正确处理LongShortByte等。

Use 'instanceof" 使用“ instanceof”

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

It is dangerous to assume that a Number subclass instance can be represented with double . 假设Number子类实例可以用double表示是危险的。 To do this safely, you need to check for all possible types. 为了安全地执行此操作,您需要检查所有可能的类型。

@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();
}

Here is a question/answer related to this. 是与此相关的问题/答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM