在Java泛型中驯服类型检查器

在Java泛型中驯服类型检查器,java,generics,Java,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

我以为我对泛型很了解,但显然我不懂

以下是问题的测试用例:

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) {}
}
import java.util.ArrayList;
类作业{}
类运行{}
类Job2扩展了作业{}
类Run2扩展了Run{}
类RunList扩展了ArrayList{}
福班{
//#1问题
public void test1(运行列表为什么){}
//#2这也不行
public void test2(运行列表为什么){}
//#3这很管用
public void test3(运行列表为什么){}
}
编译器不允许使用上面的test1方法,因为“Job”不在其类型界限内。我有点理解它---
Job
,因为原始类型不扩展
Job
,所以出现了错误。相反,test3是有效的

现在的问题是,我该如何让它工作?我试过了,但也不行。我认为这个问题与#1--
Job
非常相似,因为它的类型参数
Job
是一个原始类型,因此不在范围内

除了使用原始类型,还有人知道如何让类型检查器感到高兴吗?或者它只是在Java类型系统中无法实现?

可能:

public <J extends Job<J, R>, R extends Run<J, R>> void test(RunList<J, R> why) {}
公共无效测试(运行列表为什么){

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

你说得对,不知道我在想什么!你的评论启发我进一步思考,我对它进行了测试,问题的原因与类型变量的递归定义有关
job你能提供关于你想做什么的其他信息吗?看起来你有一个解决方案——哪一个是你想要的,为什么?注意#3在语义上是不同的,它不是一个解决方案——它甚至不是一个解决方案#3有效地为您提供了ArrayList,例如,您不能在其中添加普通运行对象。我想要一个包含普通作业和运行的运行列表,例如,我可以在其中放入一个普通运行对象#2.如果成功了,我会取得类似的成就。但我不知道为什么。添加(newjob());RunList具有R类型的元素。此类型是Run的某个子类。为了能够添加到列表中,您需要知道RunList所包含的Run的确切子类(或该Run的子类)。Run充其量与R相同,更糟糕的是R的超类型。从另一个角度来看,假设test2可以是:“why.add(new Run());”,如果您编写:RunList rl=new RuRunList();test2(rl);Run2 Run2=rl.get(0);在get()行将出现类强制转换异常。如果要执行why.add(new Run());,然后您需要将您的运行列表声明为特定类型(如Run2),或者至少声明为
?super R
。你是说没有泛型的原始类型
ArrayList
?但这比使用RunList作为原始类型更糟糕。@Willi我应该更具体一些。使用类RunList扩展ArrayList{}这也允许您添加运行对象以及任何类型R的对象。我不确定这是否会影响RunList类的其他部分“extends”的类型边界不包括右侧的类/接口;它只包括其子类/子接口“,对不起,我不这么认为。列表可以分配给T扩展数字的列表。Kohsuke,你打算如何使用泛型?您的目标是在编译时强制运行列表只包含已知与某个作业子类兼容的运行子类吗?例如,RunList是有效的,但RunList不是,因为Job2只是为了与Run2一起工作而编写的?另外,制作作业和运行接口有什么问题吗?
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>());

    }
}