【问题标题】:A way to create an interface extending comparator interface that compares current subclass only一种创建扩展比较器接口的接口的方法,该接口仅比较当前子类
【发布时间】:2015-04-11 11:02:16
【问题描述】:

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

public interface MyInterface extends Comparable<MyInterface>

所以实现的类会自动描述

compare(Subclass x)

而不是

compare(MyInterface)

这可能吗?

【问题讨论】:

  • 那我猜 Sublcas 会被定义为 Subclass 实现 MyInterface。不是这样吗?如果是这样,这是一个不错的最后手段。

标签: java generics interface java-8


【解决方案1】:

你可以这样做:

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 进行比较...

【讨论】:

  • 这是个好问题……最后一部分。让我认真思考。谢谢
  • Practical example。请注意,您可以(并且可能应该)删除类型签名的 ? super 部分。
【解决方案2】:

我用泛型重用了 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 引用,但不要对它们进行排序!在排序之前确保它们是同一类的实例。

【讨论】:

  • 所以你找到了一种复杂的方法来抛弃泛型的所有优点......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多