我正在开发Java上的原生Android应用程序,我遇到了一些意想不到的行为。看看这些课程:
public class Parent<C> {
protected C mCallback;
public void setCallback(Object callback) {
mCallback = (C)callback;
}
}
class Child<T extends Vehicle>
extends Parent<Child.Callback<Vehicle>>{
public void invoke(){
mCallback.onAction(new Vehicle());
}
public interface Callback<T> {
void onAction(T vehicle);
}
}
class Vehicle {
}
现在
Child<Vehicle> child = new Child<Vehicle>();
child.setCallback(new Object()); // I expect ClassCastException to be thrown here!
child.invoke(); //But it's thrown only here!
为什么不在.setCallback()方法中抛出ClassCastException?
为什么只有在我尝试访问Callback接口的方法时才抛出它?
如何检查对象回调是C的实例?或者我怎样才能在setCallback()方法中至少获得ClassCastException?
P.S。这是一个简化的例子!请在此处考虑相同但真实的问题:How to check typed callback type inside Fragment.onAttach()
@ luckydog32在评论here
中提出的解决方案之一public abstract class Parent<C> {
protected C mCallback;
public void setCallback(Object callback) {
mCallback = castCallback(callback);
}
protected abstract C castCallback(Object callback) throws ClassCastException;
}
class Child<T extends Vehicle>
extends Parent<Child.Callback<Vehicle>>{
@Override
protected Callback<Vehicle> castCallback(Object callback) throws ClassCastException {
return (Callback<Vehicle>)callback;
}
public void invoke(){
mCallback.onAction(new Vehicle());
}
public interface Callback<T> {
void onAction(T vehicle);
}
}
答案 0 :(得分:3)
你不能转换为C
,因为它在运行时不存在(即仅编译时),而是在setCallback定义中使用C而不是Object
答案 1 :(得分:2)
这是因为名为Type Erasure的东西。基本上在编译程序之后,泛型类型将被其上限替换。例如,
if (requestCode == WRITE_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
Uri uri = resultData.getData();
try {
OutputStream os=getContentResolver().openOutputStream(uri);
PrintStream ps=new PrintStream(os);
ps.print("Message to write");
ps.flush();
ps.close();
} catch (Exception e) {
Log.e("Some identifying string", "Exception writing to "+uri.toString(), e);
}
}
T的每个实例都被视为是一个Vehicle类。
所以在代码中:
class Child<T extends Vehicle>
在运行期间你几乎都说:
public void setCallback(Object callback) {
mCallback = (C)callback;
}
由于您正在立即进行回调,因此对代码的简单修复就是:
public void setCallback(Object callback) {
mCallback = (Object)callback;
}