2010-08-10 18 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