java 泛型方法警告 "Unchecked cast"

java generic method warning "Unchecked cast"

我写了一个方法来替代View.findViewById(int id),但是我得到了一个警告:

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

我相信这是警告的原因:Java 允许向下转换,即将类型 X 的对象转换为 X 的子class。但是,这需要检查运行。例如:

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 的子 class,这意味着转换通常会导致在运行时执行相同类型的检查.但是,由于类型擦除,程序此时在代码中实际上并没有关于 T 的 class 的信息,这意味着它无法执行检查。因此,您会收到有关使用未经检查的操作的程序的警告。程序不能保证,当这个方法returns时,返回的对象实际上是class T.

的一个实例

我尝试了一些测试用例,发现检查经常发生在调用泛型方法的语句上。假设 View2 扩展了 View,并且您想以 returns 和 View2 的方式使用 find。那么:

View2 v = YourClass.<View2>find(x, id);

如果 findViewById 找到的对象实际上不是 View2,您将得到 ClassCastException。但是:

View v = YourClass.<View2>find(x, id);

假设findViewById returns 一些其他视图。根据我的测试,这不会引发异常,即使类型参数是 View2;因为它被分配到 View,如果结果是其他视图,它会工作正常,所以不会检查 View2

String s = YourClass.<View2>find(x, id).toString();

假设findViewById returns 一些其他视图。当我尝试这个时,我认为它不会抛出异常,因为另一个视图也会有 toString()(就像所有 Object 一样)。但这确实抛出 ClassCastException

不知道有没有好的办法解决。一种可能是在 find 中添加第三个参数来表示 T 的 class,并使用它的 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);

这行得通——如果 findViewById returns 错误 class,它会从 cast() 方法中抛出异常。但是,为每次使用添加第三个参数可能并不吸引人,即使它可以让您从调用中消除显式泛型类型参数。

我认为在这种情况下可以忽略警告,并使用 @SuppressWarnings("unchecked") 阻止警告出现,如果您同意有时程序可能会继续而不是当 findViewById returns 错误的视图类型时抛出异常。

(免责声明: 我的测试是使用 Java 8 进行的。我没有使用任何在 Java 7 中无效的东西。但是如果 Android 仍然没有完全实现 Java 7,我写的一些内容可能是错误的。)