Java Generics: interface method that receives type argument of implementing class

64,916

Solution 1

What you want is not possible in Java, and is not useful.

So this should not be allowed:

Why not? What purpose does that serve? Generics is not for you to make arbitrary restrictions. Generics is only useful for eliminating casts that you would otherwise need, because it can prove that the cast is always safe.

As long as public class A implements MyInterface<B> is type-safe, there is no point in making an arbitrary restriction that prohibits it.

You should simply define your interface as

public interface MyInterface<T> {
   public void method(T object);
}

and you can define your class

public class A implements MyInterface<A> {
    public void method(A object) {
    }
}

and if somebody else defines a class

public class B implements MyInterface<A> {
    public void method(A object) {
    }
}

then so be it. Why do you care? What problem does it cause?

Solution 2

Well, this is at least possible:

public interface SelfImplementer<T extends SelfImplementer<T>> {
    void method(T self);
}

As you can see, the Generic declaration looks a bit like infinite recursion and I'm fairly sure that if Java didn't have type erasure, it would be - thankfully (?) all Generics are actually Objects after compiler has dealt with them so you can do this

public class Impl implements SelfImplementer<Impl> {
    @Override
    public void method(Impl self) {
        System.out.println("Hello!");
    }
}

and as expected, this

public static void main(String[] args) {
    Impl impl = new Impl();
    impl.method(impl);
}

prints out

Hello!
Share:
64,916
krinklesaurus
Author by

krinklesaurus

Updated on February 03, 2020

Comments

  • krinklesaurus
    krinklesaurus over 4 years

    In Java, is it possible to define an interface that has a method that receives an argument of the implementing class?

    interface:

    public interface MyInterface {
       public <T is/extends of the type of the implementing class> void method(T object);
    }
    

    class:

    public class A implements MyInterface {
    
        public void method(A object) {
           ...
        }
    
    }
    

    What I want to avoid is that a class could implement MyInterface with another class like itself.

    So this should not be allowed:

    public class A implements MyInterface<B> {
    
        public void method(B object) {
           ...
        }
    
    }    
    





    Edit:

    Ok I try to describe in another way what I want to achieve. I want to have several classes that have a method that accepts an arg of that type of class. So additionally to class A from above lets say theres another class B that looks like this:

    public class B implements MyInterface {
    
        public void method(B object) {
           ...
        }
    
    }
    

    what booth classes A and B have in common is a method called "method" that receives an arg of the type of the class itself.

    In my project I want to achieve the following. Im writing a little game and want to implement some kind of collision detection. basically I want to do this by doing some "smart" polymorphistic calls.

    I defined an interface ICollisionReceiver that looks like this:

    public interface ICollisionReceiver<T extends IShape> extends IShape {
    
        public boolean collides(T t);
    
    }
    

    and I defined another interface like this:

    public interface ICollisionChecker<T extends ICollisionChecker<T>> extends IShape {
    
        public void addCollisionReceiver(ICollisionReceiver<T> receiver);
    
        public void removeCollisionReceiver(ICollisionReceiver<T> receiver);
    
    }
    

    Now for instance my player implements the interface ICollisionReceiver as the player receives collisions and handles them. This should be done in a generic way, so for instance I have boxes and circle, now the Player implements ICollisionReceiver < Box > and ICollisionReceiver < Circle > so I have both methods

    @Override
    public boolean collides(final Box b) {        
        ...
        return false;
    }
    

    and

    @Override
    public boolean collides(final Circle c) {        
        ...
        return false;
    }
    

    In my box and circle class I can register ICollisionReceivers and then I do the following in the update method:

        boolean conti = true;
        int i=0;
        while(conti && i<collisionReceivers.size()) {
            final ICollisionReceiver<Bonus> rec = collisionReceivers.get(i);               
            if(this.collidesWith(rec)) {
                conti = rec.collides(this);
            }            
            ++i;
        }
    

    this basically checks if this box collides with a certain receiver and then calls the receivers collides() method.

    Now the point is, I want to make sure that both classes box and circle implement the ICollisionChecker interface only with their own type.

    I explicitly can do this by doing something like this

    public class Bonus extends AnimatedSprite implements ICollisionChecker<Bonus>...
    

    but this is not very satisfying for me...

    Sorry for the long post, I hope this makes it clear.