Java 对象转换无法正常工作

Java object casting doesn't work like I need it to

我正在 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 在评论中提出的解决方案之一

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

您不能转换为 C,因为它在运行时不存在(即仅编译时),而是在您的 setCallback 定义中使用 C 而不是 Object

这是因为一个叫做 Type Erasure 的东西。基本上在你的程序被编译之后,泛型类型被替换为它们的上界。例如

class Child<T extends Vehicle>

T 的每个实例都被视为车辆 class。

所以在代码中:

public void setCallback(Object callback) {
    mCallback = (C)callback;
}

在 运行 时间里,您几乎在说:

public void setCallback(Object callback) {
    mCallback = (Object)callback;
}

由于您是立即投射回调,因此您的代码的简单修复方法就是:

public void setCallback(C callback) {
    mCallback = callback;
}