【问题标题】:Recursive generic class definition and "cannot be converted" compilation error递归泛型类定义和“无法转换”编译错误
【发布时间】:2012-01-31 05:55:14
【问题描述】:

这是一种类似于您可能见过的其他 JPA BaseEntity 模式的设计:

@MappedSuperclass()
public abstract class Entity<X extends Entity<X>>
    implements
        Comparable<X>,
        Serializable
{
    private static final long serialVersionUID = 1L;
    private Long id;
    private Date timeStamp;

...

    //  Simply compare fields in subclass until difference is discovered
    private int compareSubclassFields(X that)
    {
        int result = 0;
        for(Comparator<X> comparator : getComparators())
        {
            result = comparator.compare(this,that); <<=== compilation error
            if(result != 0) { break; }
        }
        return result;
    }

    /**
     *  Entity subclasses provide a list of their own special
     *  comparators that can contribute to the comparison.
     */
    protected abstract List<Comparator<X>> getComparators();
}

这是一个扩展实体的类的示例:

public class User extends Entity<User>
{
    private static final long serialVersionUID = 1L;
    private String firstName;
    private String lastName;
    private String email;

...

    @Override
    public List<Comparator<User>> getComparators()
    {
        List<Comparator<User>> result =
            new ArrayList<Comparator<User>>();

        result.add(getLastNameComparator()); //  Sort first on last name
        result.add(getFirstNameComparator());//  Next, by first name
        result.add(getEmailComparator());    //  Finally, by email (unique)
        return result;
    }
}

编译时出现以下错误:

error: method compare in interface Comparator<T> cannot be 
       applied to given types;

        result = comparator.compare(this,that);
                                    ^
required: X,X
found: Entity<X>,X
reason: actual argument Entity<X> cannot be converted to
        X by method invocation conversion

where X,T are type-variables:
  X extends Entity<X> declared in class Entity
  T extends Object declared in interface Comparator

阅读Java Enum Definition,尤其是它所说的部分,

public class StatusCode extends Enum<StatusCode>

现在,如果您检查约束,我们得到了 Enum - 所以 E=StatusCode。让我们检查一下:E 是否扩展了 Enum?是的!我们没事。

我假设在我的示例中,X extends Entity&lt;X&gt;,'this' 将是User 的一个实例,而不是Entity&lt;User&gt;。此外,由于 Entity 是一个抽象类,它必须被扩展,因此,compareNonIdFields 只能由 X 的实例调用——在其自身上。当然,当我施放时,我会收到未经检查的警告:

warning: [unchecked] unchecked cast
        result = comparator.compare(((X)this),that);
                                        ^
required: X
found:    Entity<X>
where X is a type-variable:
  X extends Entity<X> declared in class Entity
1 warning

对于这种递归泛型用法为何会导致编译错误以及使未经检查的强制转换警告消失的解决方案的想法将不胜感激。

【问题讨论】:

    标签: java generics unchecked


    【解决方案1】:

    您正在 Entity&lt;X&gt; 类中编写 this 关键字。所以,

    this = 实体

    另一方面,您为X 提供了Comparator,而不是为Entity&lt;X&gt;

    您可以在Entity&lt;X&gt;对象中保留一个字段来存储相关的X对象并以这种方式编写:

    结果 = 比较器.compare(this.getX(),that);

    【讨论】:

      【解决方案2】:

      想象以下两个类。

      class Foo extends Entity<Bar> {}
      class Bar extends Entity<Foo> {}
      

      显然,比较不仅可以在 X 的实例上调用:如果你在 Foo 的实例上调用它,那么 X = Bar 也可以,反之亦然。

      编辑:为了清楚起见,虽然您打算始终将继承类型本身替换为 X,但这不是由语言和/或编译器强制执行的。这就是你的问题的根源。

      【讨论】:

        【解决方案3】:

        奇怪!如果你真的很高兴

        result = comparator.compare((X)this, that);
        

        那么,在什么情况下“this”可能不是 X?子类化的一些奇怪排列并使参数未绑定?或者进一步使用绑定参数对子类进行子类化?

        啊哈!如果在 X 已经绑定的情况下对类进行子类化,就会发生这种情况!

        ……不,这不对。我得承认,我很困惑。

        【讨论】:

        • 你是对的,不会出现 Entity 存在的情况,因为它是抽象的,并且每次调用该方法时,都会由其自身的子类的实例调用。类的编写方式,Entity 总是可以转换为 X。为了避免编译器未经检查的警告,我只是按照 Muhammed 的建议做了:在基类中添加 abstract X getX()result = comparator.compare(this.getX(),that);
        猜你喜欢
        • 2018-01-23
        • 2017-10-12
        • 2020-10-18
        • 1970-01-01
        • 2015-04-04
        • 1970-01-01
        • 2015-09-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多