Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I implement multiple interfaces?

I am creating a game where objects implement interfaces for animations. I have a parent interface for the animations. Here is a shortened version:

public interface Animates<S extends Animator> {
    S createAnimator(long animationTime);
}

In addition, I have multiple interfaces that extend this interface. Two examples:

public interface AnimatesPaint extends Animates<PaintAnimator> {
    PaintAnimator createPaintAnimator(long animationTime);

    default PaintAnimator createAnimator(long animationTime) {
        return createPaintAnimator(animationTime);
    }

}

and

public interface AnimatesPosition extends Animates<PositionAnimator> {
    PositionAnimator createPositionAnimator(long animationTime);

    @Override
    default PositionAnimator createAnimator(long animationTime) {
        return createPositionAnimator(animationTime);
    }

}

As you can see, the interfaces that extend Animates override the createAnimator method in order to delegate the logic of createAnimator to the class that implements the interface.

The reason I am doing this is that I want to be able to have a screen element (that can animate) that implements multiple animation interfaces (for example both AnimatesPosition to move the element around and AnimatesPaint to change its color).

However, that apparently does not work. When I implement both in one class (illustrated below), I get the compilation error:

createAnimator(long) in AnimatesPaint clashes with createAnimator(long) in AnimatesPosition; attempting to use incompatible return types

Here is an example of a class that implements both Animates interfaces:

public class ScreenElement implements AnimatesPaint, AnimatesPosition {
    @Override
    PositionAnimator createPositionAnimator(long animationTime) {
        return new PositionAnimator(animationTime);
    }
    @Override
    PaintAnimator createPaintAnimator(long animationTime) {
        return new PaintAnimator(animationTime);
    }
}

So what I don't understand is that both AnimatesPaint and AnimatesPosition already implement createAnimator. Yet, the error message seems to suggest that createAnimator also needs to be implemented by ScreenElement! If createAnimator would not have been implemented yet, I would get it, why there is a clash.

Where does my logic go wrong?

In the end, what I want to achieve, is to have a generic method that can initiate any type of animation. For example:

public class AnimationStarter<S extends Animates, T> {

    public void startAnimation(S animates, T start, T target, long animationTime) {
        Animator animator = animates.createAnimator(animationTime);
        animator.init(start, target);
        animates.setAnimator(animator);
        animator.startAnimation();
    }
}

--Edit--

Upon request, here is the declaration of Animator

public abstract class Animator<T> {}

and one of its extended classes

public class PositionAnimator extends Animator<Point>{}
like image 500
MWB Avatar asked Oct 12 '19 10:10

MWB


People also ask

Can a class implement more than one interface?

A class can implement any number of interfaces. In this case there is no ambiguity even though both the interfaces are having same method. Because methods in an interface are always abstract by default, which doesn’t let them give their implementation in interface itself. Are there any code examples left?

Why an interface cannot implement another interface in Java?

Why an interface cannot implement another interface in Java? An interface cannot implement another interface in Java. An interface in Java is essentially a special kind of class. Like classes, the interface contains methods and variables. Unlike classes, interfaces are always completely abstract.

What happens when an interface extends another interface?

An interface extends another interface because the interface that extends another interface just adds its own abstract method (s) and doesn’t provide method definitions for abstract methods of the other interface. An interface will never extend a class as interfaces don’t provide method definitions.

Why should I create an interface?

Creating an interface is a good way of grouping related functionalities. There are times when you need to bring related functionalities together into one class. being able to implement multiple interfaces gives you that flexibility.


2 Answers

So what I don't understand is that both AnimatesPaint and AnimatesPosition already implement createAnimator.

Yes, and those implementations conflict with one another. If you could do this, your resulting class's type would need to expose two createAnimator methods that are only differentiated by return type. Java doesn't let you have overloads that are only differentiated by return type, so you can't do that. A method signature, for overloading purposes, doesn't include the return type.

Even if they had the same return type (Animator), you'd then have two overloads with exactly the same signature, which you can't do.

They'll need to be separate methods — e.g., with separate signatures that can be differentiated — if they're going to be implemented in the same class.


In a comment you've asked:

But isn't the conflict resolved by the fact that the method has already been overriden by AnimatesPaint and AnimatesPosition? This way the implementing class ScreenElement doesn't need to implement createAnimator method, so no conflict will occur.

No, because the class itself exposes those methods (or rather, would need to) as part of its signature. Basically, suppose you could create the class and you had an instance of it, s. What would s.createAnimator(300L) do? Which one should the compiler choose?

A class's public type is composed of all of its public members, including all the public members of all of the interfaces it implements. So at a type level, it's impossible for two interfaces to implement methods with the same signature.

like image 57
T.J. Crowder Avatar answered Oct 25 '22 20:10

T.J. Crowder


If you call ScreenElements createAnimator() method, which one is it supposed to use? That’s what the compiler is complaining about. You need to tell it what to do when that method is called. Based on the code I’m not sure. So you are correct that ScreenElement needs to implement the create animator method, that way the compiler knows what to do when that method is called.

like image 36
Jake Luby Avatar answered Oct 25 '22 22:10

Jake Luby