Java 在接口中实现 class

Java implement class in interface

假设我有以下 classes:

public abstract class Crop {
}

public abstract class Fruit extends Crop {
}

public interface Edible /* ALWAYS IMPLEMENTED BY A CROP */ {
}

public class Apple extends Fruit implements Edible /* BOTH A CROP AND EDIBLE */ {
}

public class Holly extends Fruit /* NOT EDIBLE */ {
}

public class Wheat extends Crop implements Edible {
}

现在,我想确保每个 Edible(接口)都是 Crop(class)。

为什么我不能说:

public interface Edible implements Crop {
}

所以 Edible 本身只能由扩展 Crop?

的 classes 实现

是否有解决此问题的方法,尤其是在将 Edible 作为需要 Crop 的通用参数传递时?

您不能在接口上实现 Java Class。接口只能 extend 其他接口。因此,通过这种方式,您可以声明另一个接口(并在 Crop 上实现它)。然后,您可以在 Editable.

上扩展这个新接口

这可以是这样的:

public abstract class Crop implements NewInterface{
}

public interface Edible extends NewInterface {
}

限制 classes 可以实现接口的唯一选项是使用 sealed interface(在 Java 17 中引入),它限制了 class 可以继承的内容它。但是,您的 use-case 存在并非所有农作物都可食用的“问题”,这使事情变得复杂。

从表面上看,您的问题无法解决,除非您想在界面中明确列出所有可能的 classes。

例如,你的问题可以这样解决

public sealed interface Edible 
        permits Apple, Wheat {
}

public abstract class Crop {
}

public abstract class Fruit extends Crop {
}

public final class Apple extends Fruit implements Edible /* BOTH A CROP AND EDIBLE */{
}

public class Holly extends Fruit /* NOT EDIBLE */ {
}

public final class Wheat extends Crop implements Edible {
}

您可以使用类似以下内容来放宽一些限制:

public sealed interface Edible 
        permits EdibleFruit, Wheat {
}

public abstract class Crop {
}

public abstract class Fruit extends Crop {
}

public non-sealed abstract class EdibleFruit extends Fruit implements Edible {
}

public class Apple extends EdibleFruit /* BOTH A CROP AND EDIBLE */{
}

public class Holly extends Fruit /* NOT EDIBLE */ {
}

public final class Wheat extends Crop implements Edible {
}

但这可能会导致复杂的层次结构(例如,考虑到某些 sub-types 可食用水果是不可食用的)。

以不同的方式处理这个问题可能更有意义,例如检查可食性或毒性,或最大安全剂量,或类似的东西。

为什么不约束Edible

interface Edible<T extends Crop> {}

所以每个可食用的都必须实例化接口,如果它是子class Crop:

class A extends Crop implements Edible<A> {} // Ok
class B implements Edible<B> {} // Bad

至少每个 Edible 都需要用 class 实例化,即 Crop。但是你可以做一些奇怪的事情,比如:

class C implements Edible<A> {}