Gre*_*ack 5 java generics casting wildcard
以下代码来自名为ButterKnife的Android库.我正在弄清楚它是如何工作的.
@SuppressWarnings("unchecked") // That's the point.
public <T> T castParam(Object value, String from, int fromPosition, String to, int toPosition) {
try {
return (T) value;
} catch (ClassCastException e) {
throw new IllegalStateException("Parameter #"
+ (fromPosition + 1)
+ " of method '"
+ from
+ "' was of the wrong type for parameter #"
+ (toPosition + 1)
+ " of method '"
+ to
+ "'. See cause for more info.", e);
}
}
Run Code Online (Sandbox Code Playgroud)
我试图重新创建此函数的行为:
@SuppressWarnings("unchecked")
public static <T> T cast(Object o){
try {
return (T) o;
} catch (ClassCastException e){
throw new AssertionError("Error");
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
Object o = new String("test");
Double d = cast(o);
Run Code Online (Sandbox Code Playgroud)
但是异常并没有被捕获,它会在调用方法时被抛出.这是为什么?
另外,这是如何工作的?该方法如何知道要转换为什么?
由于类型擦除,仅在编译时检查泛型类型.这样做是因为没有办法在Java 5中的运行时中引入泛型,而不会破坏向后兼容性并强制重新编译所有已存在的库.
历史悠久,当您定义"通用"类或方法时,实际代码将被编译为Object而不是您绑定方法的类型.所有类型检查都在编译时完成.
因此,您的方法代码实际上并没有在return语句中进行强制转换,因为它将某些内容(a String)分配给Object返回值.实际的ClassCastException由调用行返回,因为它是实际键入引用变量的位置.
正如 SJuan67 所解释的,你不能像 Java 编译器那样真正使用泛型类型的强制转换
如果类型参数无界,则将泛型类型中的所有类型参数替换为其边界或对象。因此,生成的字节码仅包含普通的类、接口和方法。
有关所有仿制药限制的更多信息请参见此处。
所以 ButterKnife 代码将如下所示:
public Object castParam(Object paramObject, String paramString1, int paramInt1, String paramString2, int paramInt2)
{
return paramObject;
}
Run Code Online (Sandbox Code Playgroud)
所以对于你的问题:
问:但是异常并不是永远不会被捕获,它会在调用方法时抛出。这是为什么?
答:嗯,它甚至不在字节码中。
问:另外,这具体是如何工作的?该方法如何知道要转换到什么?
答:没有。至少不会像你想象的那样。实际上,它会抛出 ClassCastException,而不是您观察到的 IllegalStateException 或 AssertionError。您甚至可以使用 ButterKnife 示例应用程序进行尝试,并将已知的 TextView 绑定到 CheckBox:
@Bind(R.id.title) CheckBox title;
Run Code Online (Sandbox Code Playgroud)
问:那么图书馆如何运作?
答:好吧,IllegalStateException 永远不会被调用,并且您会遇到 ClassCastException。为什么会这样我不太确定。然而,当 ButterKnife 生成代码时,这可能是为了防止编译错误。
例如:
public interface Some {
}
public static void weWantSome(Some d) {
}
public static void test() {
String o = "test";
weWantSome((Some)o); //<-- compile error
weWantSome(Main.<Some>cast(o)); //<-- runtime error
}
Run Code Online (Sandbox Code Playgroud)
这就是为什么前面的示例代码可以编译但不能运行。
| 归档时间: |
|
| 查看次数: |
1515 次 |
| 最近记录: |