简体   繁体   中英

java generic method warning “Unchecked cast”

I wrote a method to substitute for View.findViewById(int id) , But I got a warning: 在此输入图像描述

Is there any problem in this method ? Or how to avoid it ?

I believe this is the reason for the warning: Java allows downcasting, that is, casting an object of type X to a subclass of X. However, this requires a check at runtime. For example:

Object x1 = <... something that returns an object that may be a String ...>;
String x2 = (String)x1;

The cast will try to treat x1 as a String . But x1 can be any Object . It may or may not be a String . The cast works only if x1 is actually a String ; otherwise you get a ClassCastException at runtime.

The problem in your code is that T is a subclass of View , which means that the cast would ordinarily cause the same kind of check to be performed at runtime. However, because of type erasure, the program doesn't actually have information about the class of T at this point in the code, which means that it can't perform the check. So you get a warning about the program using an unchecked operation. The program cannot guarantee that, when this method returns, the returned object will actually be an instance of class T .

I tried some test cases and found that the check often takes place on the statement that calls the generic method. Suppose View2 extends View , and you want to use find in a way that returns a View2 . Then:

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

If the object found by findViewById isn't really a View2 , you'll get a ClassCastException . But:

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

Suppose findViewById returns some other view. Based on my tests, this won't throw an exception, even though the type parameter is View2 ; since this gets assigned into a View , which will work fine if the result is some other view, no check for View2 ever occurs.

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

Suppose findViewById returns some other view. When I tried this, I thought that it wouldn't throw an exception, because the other view would also have toString() (like all Object s). But this did throw ClassCastException .

I don't know if there's a good way to fix it. One possibility is to add a third parameter to find to denote the class of T , and use its cast method:

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);

This works--it throws an exception from the cast() method if findViewById returns the wrong class. However, adding a third parameter to every use might not be appealing, even though it may allow you to eliminate an explicit generic type parameter from the call.

I think this is a case where it's OK to ignore the warning, and use @SuppressWarnings("unchecked") to stop the warning from showing up, if you're OK with the possibility that sometimes the program might continue instead of throwing an exception when findViewById returns the wrong kind of view.

( My tests were conducted using Java 8. I didn't use anything that wouldn't be valid in Java 7. But if Android still hasn't fully implemented Java 7, some of what I wrote could be wrong.) 我的测试是使用Java 8进行的。我没有使用任何在Java 7中无效的东西。但是如果Android仍然没有完全实现Java 7,我写的一些内容可能是错误的。)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM