一种创建扩展比较器接口的接口的方法,仅比较当前子类

时间:2015-04-11 11:02:17

标签: java generics interface java-8

我想定义一个接口,该接口强制进行比较但是针对其特定类型而不是所有父接口类型。

public interface MyInterface extends Comparable<MyInterface>

所以实现的类会自动描述

compare(Subclass x)

而不是

compare(MyInterface)

可能吗?

2 个答案:

答案 0 :(得分:2)

你可以这样做:

interface MyInterface<C extends MyInterface<C>> extends Comparable<C> {

}

这将强制实现指定自己的类型,因此:

class MyClass implements MyInterface<MyClass> {

    @Override
    public int compareTo(MyClass o) {

    }
}

但是你必须问自己,你从中获得了什么?

你必须把它传递给:

final MyInterface<MyClass> o = new MyClass();

否则它将是原型。

interface从类的实现中抽象出来,因此您应该能够传递对MyInterface的引用,并且每个人都可以访问MyInterface上定义的方法而无需关心实施班是什么。

只允许在MyClassMyClass之间进行比较,你就完全失去了这种抽象。您强制MyInterface的任何用户都知道确切的实现,因为比较两个不同的实现会产生ClassCastException

您永远无法安全地将MyInterface与另一个MyInterface进行比较,除非它们都具有相同的C - 在这种情况下,您只需将CC进行比较{1}} ...

答案 1 :(得分:1)

我将Boris的想法与泛型一起重用,并将其应用于抽象类。

interface MyInterface extends Comparable<Object> {
}


public abstract class AbstractCompareDelegator<C extends AbstractCompareDelegator<? super C>> implements MyInterface {

    @SuppressWarnings("unchecked")
    @Override
    public final int compareTo(final Object o) {
        if (!this.getClass().isAssignableFrom(o.getClass())) {
            throw new ClassCastException();
        }
        return compare(((C) o));
    }

    protected abstract int compare(final C o);
}


public class FullName extends AbstractCompareDelegator<FullName> {
    private final String firstName;
    private final String lastName;

    public FullName(final String firstName, final String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    @Override
    protected int compare(final FullName o) {
        final int firstNameDiff = firstName.compareTo(o.firstName);
        if (firstNameDiff != 0) {
            return firstNameDiff;
        }
        final int lastNameDiff = lastName.compareTo(o.lastName);
        if (lastNameDiff != 0) {
            return lastNameDiff;
        }
        return 0;
    }

    @Override
    public String toString() {
        return String.format("FullName [firstName=%s, lastName=%s]\n", firstName, lastName);
    }

    public static void main(final String[] args) {
        final Collection<MyInterface> orderedNames = new TreeSet<MyInterface>();
        // add names unordered
        final MyInterface name1 = new FullName("Luke", "Skywalker");
        orderedNames.add(name1);
        final MyInterface name2 = new FullName("Joe", "Black");
        orderedNames.add(name2);
        final MyInterface name3 = new FullName("Forest", "Gump");
        orderedNames.add(name3);
        final MyInterface name4 = new FullName("John", "Rambo");
        orderedNames.add(name4);
        // was the set ordered?
        System.out.println(orderedNames);
    }
}

Output:
[FullName [firstName=Forest, lastName=Gump]
, FullName [firstName=Joe, lastName=Black]
, FullName [firstName=John, lastName=Rambo]
, FullName [firstName=Luke, lastName=Skywalker]
]
  • 我在具体类和接口之间应用了一个抽象类。
  • 我没有限制界面中的遗传类型。我把它留作对象。我在抽象类compareTo()
  • 中进行限制
  • 我将compareTo()从抽象类委托给具体的子类compare(),用具体的类参数覆盖。
  • 现在,您可以使用 MyInterface 来引用具体的子类,而不会在引用类型中提及任何通用。
  • 您应该仔细使用 MyInterface ,因为无法比较对不同类的实例的引用(它会抛出ClassCastException,如前面的评论所述)
  • 在我的示例中,您失去了扩展其他类的具体类的可能性,因为它已经扩展了技术抽象类。这不太好。
  • 您可以将 MyInterface 引用组织到不同的集合中,但不要对它们进行排序!在排序之前确保它们是同一类的实例。