我有一个这样定义的类:
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;
它警告我,这是一个未经检查的演员。我该如何解决这个问题?
答案 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));
}
}
}