使用自引用类型时Java通用方法中的绑定不匹配错误

时间:2019-03-13 11:00:01

标签: java generics

在泛型方法中使用自引用类型时出现绑定不匹配错误,但在泛型类声明中却没有。这是错误代码的示例:

public class Container {
   public static class User<X> {}  // line 1
   public static class Box<U extends User<Box<U>>> {} // line 2
   public static class NiceBox<U extends User<Box<U>>> {}   // line 3: OK
   <U extends User<Box<U>>> void niceMethod(U user) {}   // line 4: NOT OK
}
  

在第4行上编译错误消息:绑定不匹配:类型U不是   有效替代类型< U extends Container.User<Container.Box<U>>>的有界参数Container.Box<U>

我不明白为什么,谢谢您的帮助, SC

PS:请注意,与先前提出的问题不同,此处提出的问题仅存在于泛型方法中,编译器在泛型类声明中使用时接受有问题的类型绑定。

我正在使用Java 11的编译器以及最新的Eclipse发行版。

以下是有关我要实现的目标的更多详细信息。 我正在构建一个Box,它需要在类型C的上下文中在类型T的目标上执行一些工作,其中该上下文C必须满足最小接口。 然后,我需要定义处理Box的方法(因此需要绑定自引用类型的通用方法)。 这是代码:

static class Box<T,C extends MinimalContext<Box<T,C>>> {
    void doSomething(T target, C context) {
        // do something
    }
}

interface MinimalContext<B> {   
    boolean validate(B box);
    void print(B box);
}

// FAILS:
<T,C extends MinimalContext<Box<T,C>>>
void processBox(Box<T,C> box) {}   

// Instead use:
class BoxProcessor<T,C extends MinimalContext<Box<T,C>>>    
{
    BoxProcessor(Box<T,C> box) {
        // use box as niceMethod would do 
    }
}

请注意,由于该限制仅对通用方法存在,而对类不存在,因此我正在使用内部类来完成通用方法的工作……还有其他解决方案吗?

日食开发人员可以对这个限制说更多吗?

1 个答案:

答案 0 :(得分:1)

这似乎是Eclipse编译器的限制或更高级别的严格性。 javac可以接受该代码。

在Eclipse中,您可以编写:

public static class User<T> {}
public static class Box<T extends User<Box<T>>> {}
<T extends User<Box<?>>> void niceMethod(T user) {}

然后您可以声明一个类:

static class UserBox extends User<Box<?>> {}

Eclipse将允许您:

public static void main(String[] args)
{
    Container c = new Container();

    c.niceMethod(new UserBox());
}

但是这样一来,您就无法创建具体的Box。例如:

Box<UserBox> b = new Box<>();

Eclipse不允许,但javac允许。

我怀疑Eclipse可能做正确的事,因为您在说:

“ {Box的类的类型参数将User扩展为Box的类型参数,而Box的类型参数是我们正在扩展的类型。”这对我来说听起来是不可能的,但可能是我缺少了一些东西。

编辑(因为问题已更新为显示界面)

您可以定义更严格的接口,而不是将接口定义为完全通用并尝试在Box的定义中限制上下文类型,例如:

interface BoxContext<B extends Box<?, ?>> {
    boolean validate(B box);
    void print(B box);
}

然后可以从Box的定义中删除自引用泛型:

static class Box<T, C extends BoxContext<?>> {
    void doSomething(T target, C context) {
        // do something
    }
}

然后允许您定义方法:

<T, C extends BoxContext<?>> void processBox(Box<T, C> box) {}