2010-08-10 60 views
6

我以爲我理解泛型很好,但顯然我沒有。馴服Java中的類型檢查器泛型

這是問題的測試用例:

import java.util.ArrayList; 

class Job<J extends Job<J,R>, R extends Run<J,R>> {} 
class Run<J extends Job<J,R>, R extends Run<J,R>> {} 

class Job2 extends Job<Job2,Run2> {} 
class Run2 extends Run<Job2,Run2> {} 

class RunList<J extends Job<J,R>, R extends Run<J,R>> extends ArrayList<R> {} 

class Foo { 
    // #1 problem 
    public void test1(RunList<Job,Run> why) {} 
    // #2 this doesn't work either 
    public void test2(RunList<Job<Job,Run>,Run<Job,Run>> why) {} 
    // #3 this works 
    public void test3(RunList<Job2,Run2> why) {} 
} 

編譯器不允許上述test1的方法,他說,「工作」是不是它的類型範圍內。我有點不明白--- Job作爲一個原始類型不延伸Job<Job,Run>,因此錯誤。相反,test3起作用。

現在,問題是,我該如何做這項工作?我已經嘗試了#2,但這也不起作用。我想這個問題與#1非常相似--- Job<Job,Run>不在範圍內,因爲它的類型參數Job是一個原始類型。

有沒有人知道如何使類型檢查開心,除了訴諸原始類型?或者它在Java類型系統中無法實現?

+0

你能提供你想要什麼工作的任何其他信息?看起來你有一個解決方案 - 哪一個是你想工作的,爲什麼? – mlschechter 2010-08-10 01:31:42

+0

請注意,#3在語義上是不同的,它不是解決方案---它甚至不是解決方法。 #3有效地給你ArrayList ,所以例如你不能在那裏添加普通的運行對象。 我希望RunList具有簡單的作業和運行,以便例如我可以將普通的運行對象放入其中。 #2,如果工作,會實現類似的東西。 – 2010-08-10 01:54:01

回答

1

可能:

public <J extends Job<J, R>, R extends Run<J, R>> void test(RunList<J, R> why) {} 
+0

但後來我不能做why.add(new Job()); – 2010-08-10 01:33:53

+0

相反,why.add(new Run()); – 2010-08-10 01:54:17

+0

RunList具有R類型的元素。此類型是Run的一些子類。爲了能夠添加到列表中,您需要知道RunList的確切子類(或其子類)。從另一個角度來看,假設test2可能是:「why.add(new Run());」,如果你寫:RunList rl =新RuRunList (); TEST2(RL); Run2 run2 = rl.get(0);您將在get()行上獲得類別轉換異常。 – nairb774 2010-08-10 02:09:17

0

如果更改類型參數ArrayList的,那麼你可以添加新的run();

+0

你的意思是沒有泛型的原始類型'ArrayList'? – whiskeysierra 2010-08-10 07:39:08

+0

但這比使用RunList作爲原始類型更糟糕。 – 2010-08-10 14:48:24

+0

@威利我應該更具體。使用 類運行列表置於,R延長運行>擴展的ArrayList {} 這可以讓你太添加運行對象,以及我不知道這是否會影響到類型R的任何對象RunList類的其他部分。 – 2010-08-10 23:48:39

-1

你是對的,不知道我在那裏想什麼!您的評論激發了我進一步思考,並對其進行了測試,問題的原因與類型變量Job<J extends Job<J...的遞歸定義有關,但我不完全清楚爲什麼。一種解決方法是從你的定義中刪除J和R的'使用'。

較長的答案:

import java.util.ArrayList; 

class Job<J extends Job, R extends Run> {} 
class Run<J extends Job, R extends Run> {} 

class Job2 extends Job<Job2,Run2> {} 
class Run2 extends Run<Job2,Run2> {} 

class RunList<J extends Job, R extends Run> extends ArrayList<R> {} 

class Foo { 
    // #1 works now 
    public void test1(RunList<Job,Run> why) {} 
    // #2 works now too 
    public void test2(RunList<Job<Job,Run>,Run<Job,Run>> why) {} 
    // #3 still works 
    public void test3(RunList<Job2,Run2> why) {} 
    // #4 generic method 
    public <J extends Job, R extends Run> void test4(RunList<J,R> why) {} 

    public static void main(String[] args) { 
     // Calling them even works... 
     new Foo().test1(new RunList<Job,Run>()); 
     new Foo().test2(new RunList<Job<Job,Run>,Run<Job,Run>>()); 

     // Calling the generic method works too 
     new Foo().test4(new RunList<Job,Run>()); 
     new Foo().test4(new RunList<Job<Job,Run>,Run<Job,Run>>()); 
     new Foo().test4(new RunList<Job2,Run2>()); 

     // ...sort of 

     // This doesn't work 
     //new Foo().test1(new RunList<Job<Job,Run>,Run<Job,Run>>()); 

     // This doesn't work 
     //new Foo().test1(new RunList<Job2,Run2>()); 

    } 
} 
+0

關於您對「擴展類型邊界」的聲明不包括右側的類/接口;它只包含其子類/子接口「, 對不起,但我不'你是這麼認爲的。列表可分配給列表,其中T擴展數字。 – 2010-08-10 14:47:43

+0

Kohsuke,你如何計劃使用仿製藥?你的目標是在編譯時強制你的RunList只包含已知與某個Job子類兼容的Run的子類?例如,RunList 是有效的,但RunList 不是因爲Job2只寫入與Run2一起工作? 另外,製作Job和Run接口有什麼問題嗎? – jaxzin 2010-08-12 01:56:12