在Java中被泛型混淆

时间:2015-08-06 10:50:34

标签: java generics

任何人都可以解释为什么以下代码编译?

List<Long> longNums = new ArrayList(Arrays.asList("one", "two", "three"));

是否由于类型擦除?

如果我有以下方法:

public <T> T readProperty(String propName, Class<T> type);

如何确保它会返回,比如说List<Long>而不是List<String>?显然,在调用方法的类型中,我只能提供List.class并祈祷。

//run and pray
List<Long> longNums = readProperty("prop", List.class);

我已经想到这样一个方法错误地将一个String对象列表分配给一个长号列表,直到我运行它,我才看到ClassCastException <。 / p>

5 个答案:

答案 0 :(得分:9)

您不应该期望程序正常运行,因为您没有正确使用泛型。

首先,你不应该将Generics与Raws混合,这意味着这个陈述

List<Long> longNums = new ArrayList(Arrays.asList("one", "two", "three"));

无效(就正确性而言)。如果是:

List<Long> longNums = new ArrayList<Long>(Arrays.asList("one", "two", "three"));

它甚至不会编译,你会在编译时得到错误(不是在运行时,这可能会更令人困惑和可怕)。

因此,为了编译,您的列表应定义为:

List<String> longNums = new ArrayList<>(Arrays.asList("one", "two", "three"));

此外,关于本声明

//run and pray
List<Long> longNums = readProperty("prop", List.class);

实际上无法确保readProperty将返回List<Long>,因此您必须执行强制转换或添加@SuppressWarnings注释。原因是编译器的类型擦除功能 - 参数化类型Long被删除,它在运行时消失了(实际执行readProperty()prob的值是通过反思获得。

答案 1 :(得分:1)

你错过了钻石<>(这不会编译):

List<Long> longNums = new ArrayList<>(Arrays.asList("one", "two","three"));

答案 2 :(得分:1)

这是两个不同的问题。

pom.xml

出于源兼容性原因,在这些情况下允许raw type。你不应该依赖这个,因为正如你所看到的,它打败了泛型的整个想法。

至于第二个问题,你可以通过这样的方式来回避这个问题:

<packaging>war</packaging>

它更像是一种解决方法,而不是解决方案,并不总是适用。 (例如,当您需要更复杂的返回类型时,例如List<Long> longNums = new ArrayList(Arrays.asList("one", "two", "three"));

答案 3 :(得分:0)

如果将List定义为ArrayList,则java不知道其中包含哪种对象。您可以将其分配给ArrayList<Long>,但在项目上调用方法或属性时会出现错误,因为类型不匹配。

答案 4 :(得分:0)

通用类:

public abstract class GenericClass<T> {

private T managedClass;
public List<T> readListProp(String propName,T object){
    //do stuff using T type instead of Long,String,Double,etc
}
Other classes:
public class FirstClass extends GenericClass<String>
{...
//you have a class where T from generic is replaced with String
} 
public class SecClass extends GenericClass<Double>
{...
//you have a class where T from generic is replaced with Double
}