2013-11-27 37 views
2

我有一個簡單的類,使用泛型。泛型:ClassCastException:java.lang.Object []不能轉換爲

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

我已經使用調試器來檢查參數[] PARAMS字段(在ResponseWorkerRunnable)及其組到對象[1] {表@ 4237c0e0}

所以它的對象的陣列但ResponseWorker.doInBackground期望的數組類表。

如何正確投射?

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

任何其他想法或暗示什麼可能是錯的?

------ UPDATE -------

我使用一個名爲ResponseWorkerExecutor一個單獨的類在我的代碼我安排ResponseWorkerRunnable(帶線程池)來

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); 
+0

你是否也有,當你編譯它警告? – newacct

回答

0

使用,修復它(至少那是什麼我的Eclipse說;-))

public Result doInBackground(Parameter[] param); 

如果解決了這個問題,varags聲明和泛型似乎有問題。

1

使用「參數」而不是傳統的「P」使您的代碼難以閱讀。這是發生了什麼。 this.params的類型正確設置爲Parameter []。如果您向構造函數傳遞了一個值,那麼它也會根據Parameter []進行檢查。但是,您沒有傳遞參數,因此運行時會爲您創建一個空數組。不幸的是,它不足以識別現在被擦除的類型參數,因此它創建了一個Object []。我不知道它是否應該,但事實並非如此。

我明白你在做什麼,這是有道理的。解決構造函數內部問題的一種方法是檢查「params」的類型。鑑於它是一個數組,你可能無法使用instanceof。或者,您可以簡單地檢查它是否爲空。如果您沒有收到參數[],請忽略「參數」並創建一個新的參數[]並將其分配給「this.params」。

+1

實際上,他將它作爲構造函數中的參數(表名爲t)。但我非常同意你的「P」建議。 –

+0

我已更新我的問題,並添加了代碼爲ResponseWorkerExecutor剪切 – sockeqwe

+0

「不幸的是,它不足以識別現在擦除類型參數」這沒有意義。當它看到'新的ResponseWorkerRunnable (worker,t)'時,編譯器確切知道'Parameter'在這裏,因爲它明確給出。 – newacct

2

由於Java的泛型方法的工作(在這裏閱讀有關type erasure)實際Parameter類是由在生成的字節碼Object取代,這就是爲什麼你的可變參數數組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是指。然後使用這個新數組進行可變參數調用。

+0

那麼它應該也像我建議使用Parameter []一樣工作,對嗎? –

+0

@ManuelM。我所知道的。如果方法調用'worker.doInBackground(...)'需要一個真正的'Table []'而不是一個類型被擦除的'Object []',它會失敗。當你實現一個通用接口時,經常會發生這種情況,比如'ResponseWorker <...>' – gpeche

+0

是的,那是真的。我想從泛型到ResponseWorker.doInBackground(Object ... params)中的對象,因爲我討厭類的額外參數。另一方面,我討厭將參數施加到doInBackground()中的正確對象上:-) – sockeqwe

0

所以我用一個解決方法賣掉了這個問題。我使用List而不是Parameter []或Parameter ... params。

java.util.Collections類中已經有一些幫助方法,如:Collections.singletonList(param);

所以在我看來,最好的解決方案是,因爲我只有一行代碼,我必須將單個對象放在列表<>中,或者將數組轉換爲列表。因此,這種方法是圖書館用戶不需要關心它的一個小圖書館的一部分。

Arrays.copyOf(params,params.length,actualClass))的解決方案; @gpeche建議需要一個附加的類作爲參數,最後庫的用戶必須添加該類。

所以我想我發現用列表,而不是參數的妥協...... PARAMS

+0

我認爲這是非常「不解決問題」 – newacct

+0

你是對的,更多的是解決方法! – sockeqwe