java泛型方法警告“未经检查的强制转换”

时间:2016-04-15 04:02:22

标签: java android generics findviewbyid

我写了一个替代View.findViewById(int id)的方法,但是我收到了警告: enter image description here

这种方法有问题吗?或者如何避免它?

1 个答案:

答案 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

代码中的问题是TView的子类,这意味着强制转换通常会导致在运行时执行相同类型的检查。但是,由于类型擦除,程序实际上在代码中实际上没有关于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,一些我写的可能是错的。)