【问题标题】:BaseFoo cannot be inherited with different arguments: <T,X.Bar<T>> and <T,X.Foo<T>>BaseFoo 不能用不同的参数继承:<T,X.Bar<T>> 和 <T,X.Foo<T>>
【发布时间】:2013-10-26 12:22:04
【问题描述】:

这是Java inherited Fluent method return type in multiple level hierarchies的简化版。

给定以下代码:

public enum X {
    ;
    static interface BaseFoo<T, S extends BaseFoo<T, S>> {
        S foo();
    }

    static interface Foo<T> extends BaseFoo<T, Foo<T>> {
        void foo1();
    }

    static interface BaseBar<T, S extends BaseBar<T, S>> extends BaseFoo<T, S> {
        S bar();
    }

    static interface Bar<T> extends BaseBar<T, Bar<T>>, Foo<T> {
        void bar1();
    }

}

运行javac X.java我收到错误消息:

X.java:15: error: BaseFoo cannot be inherited with different arguments: <T,X.Bar<T>> and <T,X.Foo<T>>
    static interface Bar<T> extends BaseBar<T, Bar<T>>, Foo<T> {
           ^

谁有解决办法?

声明:我正在尝试使用该模式在容器类继承层次结构中实现fluent interface

背景:为了让人们更容易理解我为什么需要这个,这是故事。我想创建一个容器系列:Traversal Sequence List。所以Traversal有一个方法Traveral&lt;T&gt; accept(Visitor&lt;T&gt;)(没有PECS简称),这个方法应该总是在遍历元素之后返回this。当我有一个List 类型时,我希望该方法返回List&lt;T&gt; 而不是Traversal&lt;T&gt;,因为我希望可以调用类似myList.accept(v).head(15) 的东西,其中head(int)List 而不是@ 的方法987654341@

【问题讨论】:

  • 我的回答 here 似乎相关。
  • @PaulBellora 这确实是一个全面的答案。好的。我想这就是 OP 在这里所需要的。
  • 是的@PaulBellora,我以前读过。但我的案例是关于一个容器继承家族,它引入了另一个&lt;T&gt; 类型。你能根据我的代码想出一个解决方案吗?
  • 好的,如果没有其他人接受挑战,我今天晚些时候再看看。
  • 我在这里删除了我的答案并将a new one 发布到原始问题中。

标签: java generics inheritance fluent fluent-interface


【解决方案1】:

类或接口不能实现或扩展通用接口的不同实例。你的Bar 接口违反了这个规则。让我们检查一下接口声明:

static interface Bar<T> extends BaseBar<T, Bar<T>>, Foo<T>

所以,Bar&lt;T&gt; 扩展了两个接口:

  • BaseBar&lt;T, Bar&lt;T&gt;&gt;
  • Foo&lt;T&gt;

除此之外,这两个接口扩展自同一接口BaseFoo 的不同实例化。

  • BaseBar&lt;T, S extends BaseBar&lt;T, S&gt;&gt; extends BaseFoo&lt;T, S&gt;
  • Foo&lt;T&gt; extends BaseFoo&lt;T, Foo&lt;T&gt;&gt;

那些继承的接口最终也是Bar接口的超级接口。因此,您的 Bar 接口尝试从 BaseFoo 的 2 个不同实例扩展,这是非法的。让我们用一个简单的例子来理解原因:

// Suppose this was allowed
class Demo implements Comparable<Demo> , Comparable<String> {
    public int compareTo(Demo arg)     { ... } 
    public int compareTo(String arg) { ... } 
}

然后在类型擦除之后,编译器将为通用方法生成 2 个桥接方法。该类被翻译成:

class Demo implements Comparable<Demo> , Comparable<String> {
    public int compareTo(Demo arg)     { ... } 
    public int compareTo(String arg) { ... } 

    // Bridge method added by compiler
    public int compareTo(Object arg)     { ... } 
    public int compareTo(Object arg) { ... } 
}

因此,这会导致在类中创建重复的桥接方法。这就是为什么它是不允许的。

【讨论】:

  • 我知道这是非法的,而我需要的是如何解决或解决它。说到这里,Bar&lt;T&gt;Foo&lt;T&gt; 的一种类型,所以我想根BaseFoo&lt;T, Foo&lt;T&gt;&gt; 可以替换为BaseFoo&lt;T, Bar&lt;T&gt;,这与通过BaseBar 的另一个继承路由相同,不是吗?
  • @green 不,不是那样的。 List&lt;Number&gt; 不是 List&lt;Integer&gt;。使用泛型时不遵循类型之间的协变关系。
  • 谢谢罗希特。无论如何工作实现我想要的,即。跨容器层次结构的流畅 API?
  • @green 我得研究一下 Fluent API 是什么。或者您可以简要说明您要做什么。可能需要更多代码。
  • 所以基本上我想创建一个Traversal Sequence List 的容器系列,同时定义了一些方法来返回this 以方便流畅的方法调用,例如@ 987654345@,当您的实例是List 类型时,您的map()filter() 应该返回List,而不是Traversal,这样您就可以编写类似myLst.map(mapFunc).head(5).append(anotherLst) 的代码,其中@987654352 @ 和 append(...)List 方法,但不是 Traversal 方法。 Java8 的 BaseStreamStream 类使用这种模式,但只在一个级别。
猜你喜欢
  • 1970-01-01
  • 2013-08-03
  • 2023-03-29
  • 2020-09-12
  • 1970-01-01
  • 2021-04-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多