0

Say I have the following 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 {
}

Now, I want to make sure that every Edible (interface) is a Crop (class).

Why can I not say:

public interface Edible implements Crop {
}

So that Edible itself can only be implemented by classes that extend Crop?

Is there a workaround for this, especially when passing Edible as a generic parameter that requires a Crop?

8
  • Because an interface extend from other interfaces ;). Classes implement interfaces Commented May 18, 2022 at 12:37
  • Hi @MadProgrammer! I do not want to extend my interface from another interface, but from a class. In this example Edible should [extend or implement] Crop, so that it itself can only be implemented by classes that extend Crop. (and potentially use Crop-methods). Commented May 18, 2022 at 12:44
  • You should write public abstract class Crop implements Edible, the reverse is not possible (and wouldn't make sense in a logical sense). If you only want subclasses of Crop to extend Edible, you should probably use sealed classes (Java 17 or higher). Commented May 18, 2022 at 12:50
  • Hi @MarkRotteveel! There are crops (in this case Holly), which are not Edible, but everything that is Edible is a Crop. So basically, the interface Edible should only be implemented by classes that extend Crop, for example Apple and Wheat, but not all classes should implement it. Commented May 18, 2022 at 12:56
  • public interface Edible implements Crop should be public interface Edible extends Crop Commented May 18, 2022 at 12:57

3 Answers 3

3

The only option to restrict what classes can implement an interface is using a sealed interface (introduced in Java 17), which restrict what class can inherit it. However, your use-case has the "problem" that not all crops are edible, which complicates matters.

On the face of it, your problem is not solvable, unless you want to explicitly list all possible classes in the interface.

For example, your problem could be solved like

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 {
}

You could relax some of the constraints by using something like:

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 {
}

But that could lead to a complicated hierarchy (e.g. consider that some sub-types of an edible fruit are not edible).

It might make more sense to handle this differently, e.g. a check on edibility or toxicity, or maximum safe dose, or something like that.

Sign up to request clarification or add additional context in comments.

2 Comments

This works, while I cannot use any methods from Crop inside of Edible. I'll go with the approach @Sergio Quinteiro, but I will use this to permit specific interfaces and Crop itself to implement NewInterface.
@Cactusroot The need to use methods of Crop inside Edible was not a constraint mentioned in your question. But yes, using an interface implemented/extended by both Crop and Edible is then the only option.
2

You cannot implement a Java Class on an Interface. Interfaces can only extend other interfaces. So, in that way, you can declare another interface (and implement it on Crop). Then, you can extend this new interface on Editable.

This can be something like:

public abstract class Crop implements NewInterface{
}

public interface Edible extends NewInterface {
}

2 Comments

Wow, nice approach! I will need to accept that I cannot use final methods with this approach.
Be warned though, this doesn't prevent classes other than Crop to implement this.
0

Why not constraint Edible?

interface Edible<T extends Crop> {}

so that every edible must instanciate the interface if it subclass Crop:

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

At least every Edible needs to be instantiated with a class that is a Crop. But you can do weird things like:

class C implements Edible<A> {}

1 Comment

I am using such a structure already for self-generics, it's just that Edible is still not a Crop and thus cannot be used as a generic resolver if it is generic itself.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.