泛型:ClassCastException:java.lang.Object []无法强制转换为

时间:2013-11-27 14:23:11

标签: java generics classcastexception

我有一个使用泛型的简单类。

public class ResponseWorkerRunnable<Parameter, Result> implements Runnable {

private final ResponseWorker<Parameter, Result> worker;

/**
 * The parameters for {@link ResponseWorker#doInBackground(Object...)}
 */
private final Parameter[] params;

public ResponseWorkerRunnable(ResponseWorker<Parameter, Result> worker,
        Parameter... params) {

    uiThreadHandler = new Handler(Looper.getMainLooper());

    this.worker = worker;
    this.params = params;
}

@Override
public void run() {

    try {

        Result res = worker.doInBackground(params);
        postResultBack(res);

    } catch (Exception e) {
        postErrorBack(e);
    }

}
}

和我的ResponseWorker:

public interface ResponseWorker<Parameter, Result> {

    public Result doInBackground(Parameter... param) throws Exception;
}

问题是,我得到了ClassCastException:

  

java.lang.ClassCastException:java.lang.Object []无法强制转换为   model.Table []

我这样做:

Table t = new Table();
ResponseWorker<Table, SuperTable> worker = ... ;

ResponseWorkerRunnable<Table, SuperTable> r = new ResponseWorkerRunnable<Table, SuperTable>(worker, t);

将安排ResponseWorkerRunnable并将在以后运行此异常:

  

java.lang.ClassCastException:java.lang.Object []无法强制转换为   model.Table []

在ResponseWorkerRunnable run()方法的这一行:

Result res = worker.doInBackground(params);

我使用调试器检查Parameter [] params字段(在ResponseWorkerRunnable中)并将其设置为Object [1] {Table @ 4237c0e0}

所以它是一个对象数组,但ResponseWorker.doInBackground需要一个类Table的数组。

如何正确投射?

Result res = worker.doInBackground((Parameter[]) params);

任何其他想法或暗示可能出错的地方?

------更新-------

我使用名为ResponseWorkerExecutor的单例类调度ResponseWorkerRunnable(使用ThreadPool)

    class ResponseWorkerExecutor {

public static <Parameter, Result> Future<?> submit(
            ResponseWorker<Parameter, Result> responseWorker, Parameter ... params) {

        return INSTANCE.executor
                .submit(new ResponseWorkerRunnable<Parameter, Result>(
                        responseWorker, params));

    }
}

所以在我的代码中我做了这样的事情: 我做这样的事情:

Table t = new Table();
// ResponseWorker implementation
ResponseWorker<Table, SuperTable> worker = ... ;

// Here is the problem with the args
ResponseWorkerExecutor.submit(worker, t);

4 个答案:

答案 0 :(得分:2)

由于泛型在Java中的工作方式(在此处阅读type erasure),实际的Parameter类在生成的字节码中被Object替换,这就是为什么你的varargs数组是Object[]而非Table[]

在这种情况下有一种解决方法应该可行,它涉及对代码的一些更改:

// Pass the actual class object to your Runnable, in this case t.getClass() -> Table.class
ResponseWorkerRunnable<Table, SuperTable> r = new ResponseWorkerRunnable<Table, SuperTable>(worker, t, t.getClass());

然后:

public class ResponseWorkerRunnable<Parameter, Result> implements Runnable {

    private final ResponseWorker<Parameter, Result> worker;

   /**
    * The parameters for {@link ResponseWorker#doInBackground(Object...)}
    */
   private final Parameter[] params;

   private final Class<?> actualClass;

   public ResponseWorkerRunnable(ResponseWorker<Parameter, Result> worker, Parameter... params, Class<?> actualClass) {

        uiThreadHandler = new Handler(Looper.getMainLooper());

        this.worker = worker;
        this.params = params;
        this.actualClass = actualClass;
    }

    @Override
    public void run() {

        try {

            Result res = worker.doInBackground((Parameter[]) Arrays.copyOf(params, params.length, actualClass));
            postResultBack(res);

        } catch (Exception e) {
            postErrorBack(e);
        }
    }
}

这样做是为了Object[]并将其内容复制到一个新的真实Parameter[]中,无论实际的Parameter类是什么意思。然后它使用这个新数组调用varargs。

答案 1 :(得分:1)

使用“参数”代替传统的“P”会使您的代码难以阅读。这是怎么回事。 this.params的类型正确设置为Parameter []。如果将值传递给构造函数,则还将根据Parameter []进行检查。但是,您没有传递参数,因此运行时会为您创建一个空数组。不幸的是,它不够聪明,无法识别现在擦除的类型参数,因此它创建了一个Object []。我不知道它是否应该,但事实并非如此。

我理解你在做什么,这是有道理的。在构造函数中“修复”问题的一种方法是检查“params”的类型。鉴于它是一个数组,您可能无法使用instanceof。或者,您只需检查它是否为空。如果您没有收到参数[],请忽略“params”并创建一个新的,emtpy参数[]并将其指定给“this.params”。

答案 2 :(得分:0)

使用,修复它(至少就是我所说的那些;-))

public Result doInBackground(Parameter[] param);

如果修复它,则varags声明和泛型似乎存在问题。

答案 3 :(得分:0)

所以我用解决方法卖掉了这个问题。我使用List而不是Parameter []或Parameter ... params。

java.util.Collections类中已经有一些帮助方法,如:Collections.singletonList(param);

所以在我的情况下,在我看来,这是最好的解决方案,因为我只有一行代码,我必须在List&lt;&gt;中放置一个对象。或者将数组转换为列表。因此,这个方法是一个小库的一部分,库的用户不必关心它。

使用Arrays.copyOf(params,params.length,actualClass))的解决方案; @gpeche建议需要一个aditional Class作为参数,最后库的用户必须添加该类。

所以我猜我通过使用List代替参数... params

找到了妥协