答案 0 :(得分:4)
我相信这就是警告的原因:Java允许向下转换,即将类型X的对象转换为X的子类。但是,这需要在运行时进行检查。例如:
Object x1 = <... something that returns an object that may be a String ...>;
String x2 = (String)x1;
演员将尝试将x1
视为String
。但x1
可以是任何Object
。它可能是也可能不是String
。仅当x1
实际上是String
时,演员才有效;否则你在运行时得到ClassCastException
。
代码中的问题是T
是View
的子类,这意味着强制转换通常会导致在运行时执行相同类型的检查。但是,由于类型擦除,程序实际上在代码中实际上没有关于T
类的信息,这意味着它无法执行检查。因此,您将使用未经检查的操作收到有关该程序的警告。程序无法保证,当此方法返回时,返回的对象实际上将是类T
的实例。
我尝试了一些测试用例,发现检查通常发生在调用泛型方法的语句中。假设View2
扩展View
,并且您希望以返回find
的方式使用View2
。然后:
View2 v = YourClass.<View2>find(x, id);
如果findViewById
找到的对象实际上不是View2
,那么您将获得ClassCastException
。但是:
View v = YourClass.<View2>find(x, id);
假设findViewById
返回其他一些视图。基于我的测试,即使类型参数为View2
,也不会抛出异常;因为这被分配到View
,如果结果是其他视图,它将正常工作,不会检查View2
。{/ p>
String s = YourClass.<View2>find(x, id).toString();
假设findViewById
返回其他一些视图。当我尝试这个时,我认为它不会抛出异常,因为另一个视图也会有toString()
(就像所有Object
一样)。但这确实抛出了ClassCastException
。
我不知道是否有一个好方法可以修复它。一种可能性是向find
添加第三个参数以表示T
类,并使用其cast
方法:
public static <T extends View> T find(View view, int id, Class<T> theClass) {
return theClass.cast(view.findViewById(id));
}
View v = YourClass.find(x, id, View2.class);
这样做 - 如果cast()
返回错误的类,它会从findViewById
方法抛出异常。但是,为每次使用添加第三个参数可能不太吸引人,即使它可能允许您从调用中消除显式泛型类型参数。
我认为这是一个可以忽略警告的情况,并使用@SuppressWarnings("unchecked")
来阻止警告显示,如果你可能有时程序可能会继续而不是抛出警告findViewById
返回错误视图时的异常。
(免责声明:我的测试是使用Java 8进行的。我没有使用任何在Java 7中无效的东西。但是如果Android还没有完全实现Java 7,一些我写的可能是错的。)