如果没有警告,则无法将Object强制转换为泛型

时间:2014-01-24 18:03:28

标签: java generics

我有一个这样定义的类:

public class SizeCache<T extends Identifiable> implements Observer {}

Identifiable只是一个定义了几种方法的接口。

我有一个方法:

public T put(final T item) {}

这会在列表中添加一个项目,通常直接使用类型为T的项目调用,但可以来自Observer,所以在我的Observer中我想确保它是T类型。

但是,我不能这样写:

public void update(Observable observable, Object data) {
if (data instanceof T) {}
}                   

因为它告诉我我需要使用它的擦除标识。

但是,当我把它投射到Identifiable

Identifiable dataItem = (Identifiable) data;

对put(dataItem)的调用失败,put(T)方法不适用于参数。

如果我转向真实类型T

T dataItem = (T) data;

它警告我,这是一个未经检查的演员。我该如何解决这个问题?

3 个答案:

答案 0 :(得分:2)

没有绕过这个事实,这是一个未经检查的演员。由于类型擦除,Java无法在运行时检查它是否为T

提供运行时检查的一种方法是让Class<T>方法使用update。您的观察者可以在构造函数中使用Class<T>,您可以将其存储起来以供update以后使用。然后你可以拨打isInstance

if (clazz.isInstance(data))

您仍然需要投放到T,但由于您现在通过此项检查确保了类型安全,因此您可以使用@SuppressWarnings("unchecked") update注释取消警告方法

答案 1 :(得分:1)

在某些情况下,如果没有警告就无法逃脱。 在您的情况下,如果您完全确定您将收到T类型的对象,则可以禁止这样的警告:

@SuppressWarnings("unchecked")

如果要检查运行时类型,您需要在班级中使用Class<T>对象,并将其与输入data进行比较,如下所示:

dataClass.isInstance(data);

请确保您在语句左侧显示dataClass,因为isInstance会检查null值,但如果data为空,您将获得NullPointerException

答案 2 :(得分:0)

由于类型擦除,运行时不会跟踪用于创建对象的实际类型参数。但是,您可以通过将T的Class对象传递给泛型类型的构造函数来自行跟踪此信息,并将该类对象用于instanceof和cast:

public class SizeCache<T extends Identifiable> implements Observer {
    private final Class<T> tClass;

    public SizeCache(Class<T> tClass) {
        this.tClass = tClass;
    }

    public void update(Observable observable, Object data) {
        if (tClass.isInstance(data)) {
            put(tClass.cast(data));
        }
    }
}