在Java Generics中驯服类型检查器

时间:2010-08-10 01:14:49

标签: java generics

我以为我很了解Generics,但显然我没有。

以下是问题的测试用例:

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<Job,Run>,因此错误。相比之下,test3可以工作。

现在,问题是,我该如何做这项工作?我已经尝试了#2,但这也不起作用。我认为问题非常类似于#1 --- Job<Job,Run>不在范围内,因为它的类型参数Job是原始类型。

除了诉诸原始类型之外,有谁知道如何使类型检查器满意?或者只是在Java类型系统中无法实现?

3 个答案:

答案 0 :(得分:1)

也许:

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

答案 1 :(得分:0)

如果将type参数更改为ArrayList,则可以添加新的Run();

答案 2 :(得分:-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>());

    }
}