递归泛型类定义和“无法转换”编译错误

时间:2012-01-31 05:55:14

标签: java generics unchecked

这是一个类似于您可能已经看过的其他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<X>,'this'将是User而不是Entity<User>的实例。此外,因为实体是一个抽象类,所以必须进行扩展,因此,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

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

3 个答案:

答案 0 :(得分:2)

您正在this课程中编写Entity<X>个关键字。所以,

this = Entity<X>

另一方面,您为Comparator提供了X,而不是Entity<X>

您可以保留一个字段以在X对象中存储相关的Entity<X>对象,并以这种方式写入:

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

答案 1 :(得分:1)

想象一下以下两个类。

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

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

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

答案 2 :(得分:0)

奇怪!如果你

,那真是太开心了
result = comparator.compare((X)this, that);

那么,是否有任何情况下&#34;这个&#34;可能不是X?子类化的一些奇怪的排列和保持参数未绑定?或者使用绑定参数进一步子类化子类?

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

......不,那不对。我得承认,我感到很沮丧。