Java泛型和继承(特定问题)

时间:2015-08-01 18:56:15

标签: java generics inheritance

我希望继承泛型类和接口。有一个我无法理解的问题。该问题反映在以下简化代码中:

public interface A1 <T extends F1<?>> {
    public void compare(T f1, T f2);
}

public class F1 < T extends A1<? extends F1<T>> >
{
    T a;
    public void compare(F1<T> f) {
        a.compare(this, f);
    }
}

A1位于A1.javaF1位于F1.java

我收到编译时错误:

The method compare(capture#1-of ? extends F1<T>, capture#1-of ? extends F1<T>) 
in the type A1<capture#1-of ? extends F1<T>> is not applicable for the 
arguments (F1<T>, F1<T>)

我需要A1 < ? extends F1< T>>来继承F1

的类

其他信息(编辑后):

我想有2个等级(&#34; O&#34;而不是&#34; F&#34;,&#34; C&#34;而不是&#34; A&#34;):

  • 第一层的类(O1O2 ...)包含对象的所有相关信息以及&#34;比较器&#34; (任何分析一对相同类型的2个对象的函数)。对象的类定义了它接受的比较器的类型,主要要求是比较器应该接受托管对象类型的2个对象。例如,O1只能接受比较O1的所有比较器,O2可以有接受O2的比较器。
  • 类的第二层次是比较器(C1C2 ...)本身。他们比较层次结构1中的对象。

两个层次结构中的每个元素都添加了在子类中使用的补充功能。

让我们考虑以下用例,这是通过这些层次结构的路径之一:

  • O1有2个成员(不是类型!):val(任何类型),cmp(类型C1仅接受O1)。
  • C1_1没有相应的对象O,但它实现了与集合相关的其他功能。它可以比较对象(&#34;基本&#34;类型如intStringTColor和&#34;复杂&#34;对象O&#39 ; s)在集合中并应用仅返回1个值(例如最大值)的聚合器。 如果集合是基本类型,则cmp2用于比较集合中的元素。对于集合中的复杂对象,可以使用它们的集成比较器。
  • C1_1_1实现了如何比较对象列表(1:1)。 C1_1_2(未提供)可用于比较对象集,例如与十字架产品。
  • O1_1的{​​{1}}类val TVALB和比较extend List<TVALA>

C1_1_1的其他子类可以有更精细的实现来比较基本对象和复杂对象。

支持代码:

C1_1_1/2

我使用依赖注入来为特定类中的比较器(public abstract class O1 <TVAL, TC extends C1<? extends O1<TVAL>>> { TVAL val; TC cmp; public double compare(O1<TVAL, TC> o) { return cmp.compare(this, o); } } public interface C1 <TO extends O1<?, ?> > { public double compare(TO t1, TO t2) { // ... } } public abstract class C1_1 < TVALA, TVALB extends Collection<TVALA>, TO extends O1<TVALB, ?> > extends C1 <TO> { Cmp2<TVALA, Double> cmp2; IAggregator<TVALA> aggr; Double compare(TO o1, TO o2) { return aggr.apply( compPairs(o1.val, o2.val, cmp2) ); } abstract pairs<TVALA> compPairs( TVALB b1 , TVALB b2 , Cmp2<TVALA> cmp2); // aggregation public static class Aggr1<TVALA> implements IAggregator<TVALA> { public Double apply(pairs<TVALA> pairs) { //... } } public static class Aggr2<TVALA> implements IAggregator<TVALA> { // ... } } public abstract class C1_1_1 < TVALA, TVALB extends List<TVALA>, TO extends O1<TVALB, ?> > extends C1_1 <TO> { pairs<TVALA> compPairs( TVALB b1 , TVALB b2 , Cmp2<TVALA> cmp2) { // ... } } public abstract class O1_1 < TVALA extends O1<?,?>, TVALB extends List<TVALA> , TC extends C1_1_1<TVALA, TVALB, ? extends O1_1<TVALA, TVALB, TC>>> extends O1<TVAL> { // ... } - 树到对象C)分配。因此,这种方法(如果可行的话)可以灵活地为特定类型的对象选择合适的比较器。

3 个答案:

答案 0 :(得分:1)

让我们首先重命名类型变量,因为两个T代表不同的东西,希望它能让事情更清晰:

public interface A1 <T extends F1<?>> {
    public void compare(T t1, T t2);
}

public class F1 < S extends A1<T extends F1<S>> >
{
    S s;
    public void compare(F1<S> f) {
        s.compare(this, f);
    }
}

现在您看到您实际上在compare上调用了s,这是A1<T>的一个实例,其中T可以是F1<S>的子类。但是,您传递的参数类型为F1<S>,而不是子类T,这正是编译器所说的。

基本上你使方法参数变得协变,可能它们应该是逆变的。为此,请使用super代替extends

public class F1 < S extends A1<? super F1<S>> >
{
    S s;
    public void compare(F1<S> f) {
        s.compare(this, f);
    }
}

答案 1 :(得分:1)

问题是a的类型为A1<? extends F1<T>>,即通过通配符进行参数化。您不能再调用A1<?>.compare,因为编译器不知道?代表什么特定类型。

对于这个更简单的代码,您会看到相同的行为:

A1<? extends Object> a = ...;
a.compare(new Object(), new Object());

如果我正确理解您的用例,您只希望能够在特定比较器上参数化F1。所以看起来你应该能够做到这一点:

interface A1<A extends A1<A>> {
    public void compare(F1<A> f1, F1<A> f2);
}

class F1<A extends A1<A>> implements Comparable<F1<A>> {
    A a;
    @Override
    public void compareTo(F1<A> f) {
        a.compare(this, f);
    }
}

请注意,我已F1实施Comparable,因为这是一种很好的做法。

答案 2 :(得分:1)

您可以删除A1课程,只需使用Comparable界面。

public class F1<T extends Comparable<T>> implements Comparable<F1<T>> {
    T t;

    @Override public int compareTo(F1<T> other){
        return t.compareTo(other.t);
    }
}