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;
}
我正在 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;
}