1

Is there a way to avoid a class from implementing 2 specific interfaces at the same time, in Java?

If, for example, I have 2 kinds of object: Movable objects and Motionless objects. Then I have a class Car which implements Movable. How can I avoid it from implementing Motionless if it already implements Movable?

This is just a trivial example, it's obvious which an object which I can move can't be motionless, but there may be circumstances where it isn't that clear that an object cannot implements 2 specific interfaces at the same time, from a logical point of view.

Andrei Suvorkov
  • 5,559
  • 5
  • 22
  • 48
Lapo
  • 882
  • 1
  • 12
  • 28
  • 4
    Provide [two `default` implementations of a single method](https://stackoverflow.com/a/22685931/2970947). – Elliott Frisch May 25 '18 at 16:14
  • You can check which interface a class implements using instanceof. See https://stackoverflow.com/questions/13487765/how-instanceof-will-work-on-an-interface – royalghost May 25 '18 at 16:15
  • @ElliottFrisch Wow this is a very elegant way to reach my goal, I didn't thought about it. Thank you! – Lapo May 25 '18 at 16:21
  • No easy way to do it in java, and the reason is it's rarely the right thing to do. A car can be motionless in some circumstances. –  May 25 '18 at 16:27
  • @ElliottFrisch That still won't work. The compiler will only force classes to provide an implementation of the conflicting default methods, after which the concrete classes will still be able to implement both interfaces at the same time. – ernest_k May 25 '18 at 16:34
  • @ErnestKiwele This is true but at least the developer has a sort of *warning*, especially if the conflicting methods have an evocative name. This is not the final solution of course and pheraps it isn't *formally correct*, but at least the one which comes closer to solving my problem. – Lapo May 25 '18 at 16:47
  • @MarcoRossi Of course the API developer makes the call. It's just unfortunate that default methods will be used for almost exactly the opposite of their reason for being. – ernest_k May 25 '18 at 16:56
  • 1
    @ErnestKiwele If the methods have different return types then the conflict becomes irresolvable. This is less about default methods in that case and more just about interface contracts in general. – Trevor Freeman May 25 '18 at 17:31

5 Answers5

2

Broadly speaking, it's up to implementers of an interface to satisfy its contract — there's no way for the interface to enforce that — and if two interfaces have mutually exclusive contracts, then implementers should recognize that while trying to satisfy the contracts.

In some cases it can be worth mentioning this in the Javadoc; for example, the Javadoc for java.util.Set mentions that its specification of 'equals' is mutually exclusive with that of java.util.List.

ruakh
  • 175,680
  • 26
  • 273
  • 307
  • Thanks for the answer. I know it's up to implementers to satisfy the contract of an interface (also looking at documentation), but I'd like to know if there was a more *scientific* method. I mean, I'm just 15 years old and in my little personal projects this is not a big deal, since I'm the only person to work on these projects. It was more a general question, not a real problem for me atm. I was thinking, can't I use annotations to create this kind of *aut aut* interfaces? Sorry for my english, i'm Italian. – Lapo May 25 '18 at 16:41
2

You can do this by having each interface declare a method with an incompatible return type.

E.g. one interface could declare a void method someMethod and the other could declare it as type int.

If you make them default then implementing classes would not have to implement them directly, and there is no way a class can successfully implement both.

e.g.

public interface A {
    default void someMethod() {}
}

public interface B {
    default int someMethod() {
        return 0;
    }
}

public class Test implements A, B
{
    // Can't make this work since we cannot successfully override
    // both default methods due to the different return types.
    @Override
    public void someMethod()
    {
        // TODO Auto-generated method stub
        A.super.someMethod();
    }
}
Trevor Freeman
  • 7,112
  • 2
  • 21
  • 40
  • Won't this work even though the 2 default methods have the same return type, as suggested by Elliott Frisch in the first comment under the question? By the way thanks for the answer, I really like this way to reach my goal. – Lapo May 25 '18 at 17:22
  • 1
    @MarcoRossi If they have the same return type then you can override and implement them in the class, if they have different return types then you cannot ever have a class that implements both interfaces. – Trevor Freeman May 25 '18 at 17:25
  • This is true. I think this is the final answer. Thank you! – Lapo May 25 '18 at 17:32
0

You cannot do this. You could do one of the following

  1. Make Movable and Motionless abstract classes.
  2. Make Movable and Motionless package-private and place them in different packages. But this would force all implementations of them to be in the same package.
Thiyagu
  • 17,362
  • 5
  • 42
  • 79
  • Thanks for the answer. I think that if I use abstract classes I can extend only one of those abstract classes, but then how could I do if I have to extend others abstract classes which excluded each other? I like the second suggestion but I think that having to implement classes in one specific package can become a problem if the project isn't small. Sorry form my english. – Lapo May 25 '18 at 16:36
  • You are correct. You can only extend from one class. AFAIK there is no straight way to do. I just gave a couple of options – Thiyagu May 25 '18 at 16:44
  • Maybe there isn't a straight way because it isn't very correct to have interfaces which excluded each other? I don't know, I'm just trying to understand why Java (and I think all languages) hasn't a straight way. I'm pretty new to programming and I develope personal apps on my own, but I've already experienced a couple of cases where having this kind of option would have been useful. – Lapo May 25 '18 at 16:54
0

There's no way of forcing that in Java.

You can force the same thing by changing your API to use abstract classes instead of interfaces:

abstract class Movable{}
abstract class Motionless{}

Only one of the two can be inherited at a time.

ernest_k
  • 44,416
  • 5
  • 53
  • 99
  • Thanks, but I think I can't apply this method since my class should extends more than one of these kind of *aut aut* abstract classes. But of course this isn't possible. – Lapo May 25 '18 at 16:27
0

As other answer you can't do this in Java. Because every method have a signature and with this you are having two same signatures and that is why it will throw a compile error. Check the Docs of Method Signiature

Gatusko
  • 2,503
  • 1
  • 17
  • 25
  • Sorry, but I don't get how this is related to my question. Are you suggesting me to use a pattern similiar to the one suggested by @ElliottFrisch in the comment under the question? – Lapo May 25 '18 at 16:30