我写了一个方法来代替View.findViewById(int id),但是我得到了一个警告:
这种方法有什么问题吗?还是如何避免呢?
解决方法:
我相信这是发出警告的原因:Java允许向下转换,即将类型X的对象强制转换为X的子类.但是,这需要在运行时进行检查.例如:
Object x1 = <... something that returns an object that may be a String ...>;
String x2 = (String)x1;
强制转换将尝试将x1视为字符串.但是x1可以是任何对象.它可以是字符串,也可以不是.仅当x1实际上是一个String时,转换才有效;否则在运行时会收到ClassCastException.
代码中的问题是T是View的子类,这意味着强制转换通常会导致在运行时执行相同类型的检查.但是,由于类型擦除,该程序实际上在代码中此时没有有关T类的信息,这意味着它无法执行检查.因此,使用未检查的操作,您会收到有关程序的警告.程序不能保证当此方法返回时,返回的对象实际上将是类T的实例.
我尝试了一些测试用例,发现检查通常在调用泛型方法的语句上进行.假设View2扩展了View,并且您想以返回View2的方式使用find.然后:
View2 v = YourClass.<View2>find(x, id);
如果findViewById找到的对象实际上不是View2,则将收到ClassCastException.但:
View v = YourClass.<View2>find(x, id);
假设findViewById返回其他视图.根据我的测试,即使type参数为View2,也不会引发异常.由于将其分配给一个View,如果结果是其他视图,则可以正常工作,因此不会对View2进行检查.
String s = YourClass.<View2>find(x, id).toString();
假设findViewById返回其他视图.尝试此操作时,我认为它不会引发异常,因为其他视图也将具有toString()(就像所有Objects一样).但这确实引发了ClassCastException.
我不知道是否有解决它的好方法.一种可能性是添加第三个参数以查找表示T的类,并使用其强制转换方法:
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);
这行得通-如果findViewById返回错误的类,它将从cast()方法引发异常.但是,即使在每次使用中都添加第三个参数可能并不吸引人,尽管它可以使您从调用中消除显式的泛型类型参数.
我认为在这种情况下,可以忽略警告,并使用@SuppressWarnings(“ unchecked”)停止警告的显示,如果可以的话,有时程序可能会继续运行而不抛出异常当findViewById返回错误的视图类型时.
(免责声明:我的测试是使用Java 8进行的.我没有使用在Java 7中无效的任何东西.但是,如果Android仍未完全实现Java 7,我写的某些内容可能是错误的.)