【问题标题】:How can i make an interface in java with a function that accepts a parameter of the type that extends the interface?如何在 java 中使用接受扩展接口类型的参数的函数创建接口?
【发布时间】:2019-02-21 14:14:55
【问题描述】:

如何在 java 中使用一个函数创建一个接口,该函数接受扩展接口类型的参数?

以接口ISelfComparable为例

如果 A 类扩展它,那么我希望它能够实现

bool compareTo(A other)

但如果 B 类扩展它,那么我希望它能够实现

bool compareTo(B other)

我知道我可以使用通用接口,但它似乎不正确,因为 A 扩展 ISelfComparable 没有任何意义

如果这是不可能的,在这种情况下最好的做法是什么?

【问题讨论】:

  • 这仍然允许 A 扩展 ISelfComparable 如果 B 也是自我可比的,或者我不明白你。
  • “我知道我可以使用通用接口,但它似乎不正确,因为 A 扩展 ISelfComparable 没有任何意义” .... 什么? A 将是class A implements ISelfComparable<A>,B 将是class B implements ISelfComparable<B> ...你从哪里得到 A 通过 B?还是你想阻止 A 超越 B?那你应该这么说。
  • 因为理论上 A 可以扩展 ISelfComparable
  • 据我所知,这种情况没有可靠的解决方案,因此需要运行时检查才能完全确定。
  • 例如,您可以在 foo 方法中尝试 System.out.println("this: " + this.getClass().getSimpleName() + " --> other: " + other.getClass().getSimpleName());,看看如何从那里开始。

标签: java interface


【解决方案1】:

通常的解决方案是自界泛型,如 Enum 类中所示。

interface Example<T extends Example<T>> {
    void foo(T t);
}

public class ExampleImpl implements Example<ExampleImpl> {
    @Override
    public void foo(ExampleImpl example) {
    }
}

它的工作原理有点令人眼花缭乱,但解释得很好,例如herehere这个题目也有很好的回答。

请注意,它并非万无一失,因为它允许这样做:

public class ExampleImpl2 extends Example<ExampleImpl {
    @Override
    public void foo(ExampleImpl example) {

    }
}

但在实践中,自界成语用于准确表达您所追求的东西。

如果您真的、真的、真的需要参数对象始终是与this 完全相同的类,则必须进行运行时检查。 (它也提出了你为什么需要这个的问题,但这会让我们偏离主题。)

【讨论】:

  • 嗯,似乎没有解决 OPs 问题。当我创建class ExampleImpl2 implements Example&lt;ExampleImpl2&gt; 时,我可以将ExampleImpl 更改为class ExampleImpl implements Example&lt;ExampleImpl2&gt;,这就是OP 喜欢阻止的。
  • @Tom 确实没有。 AFAIK 没有办法在 Java 类型系统中表达这个确切的要求,这是你能得到的最接近的。
  • 这也是我的假设。 OP 需要检查传递的 example 对象的运行时类型,如果它完全匹配 this 以完全确定。
  • 关于这个主题的规范 SO 线程可能是 Java Enum definition
【解决方案2】:

看看java.lang.Comparable类:它有一个参数,可以使用int compareTo的对象类型。

以此类推:

public interface ISelfComparable<T extends ISelfComparable<T>> {
    boolean compareTo(T other);
}

【讨论】:

  • Comparable 没有 OP 喜欢应用的限制。另请参阅另一个答案,它表明您的自界泛型也不满足该要求。
【解决方案3】:

有一种方法可以检查参数的类型,但只能在运行时检查。例如,您可以在默认方法中实现类型检查:

interface ISelfComparable {
    default boolean compareTo(ISelfComparable param) {
        if (this.getClass() != param.getClass()) {
            throw new IllegalArgumentException();
        }
        ...
    }
}

那么这个接口的每个实现应该是这样的:

class A implements ISelfComparable {
    @Override
    public  boolean compareTo(ISelfComparable param) {
        ISelfComparable.super.compareTo(param);
        ...
    }
}

在这种情况下,如果你调用new A().compareTo(new B());,那么java.lang.IllegalArgumentException 将被抛出

【讨论】:

    猜你喜欢
    • 2021-08-07
    • 1970-01-01
    • 1970-01-01
    • 2021-08-07
    • 2022-12-06
    • 2019-06-08
    • 1970-01-01
    • 2021-03-27
    • 2022-06-11
    相关资源
    最近更新 更多