web-dev-qa-db-fra.com

Java Generics: méthode d'interface qui reçoit l'argument type de la classe d'implémentation

En Java, est-il possible de définir une interface qui a une méthode qui reçoit un argument de la classe d'implémentation?

interface:

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

classe:

public class A implements MyInterface {

    public void method(A object) {
       ...
    }

}

Ce que je veux éviter, c'est qu'une classe pourrait implémenter MyInterface avec une autre classe comme elle.

Donc, cela ne devrait pas être autorisé:

public class A implements MyInterface<B> {

    public void method(B object) {
       ...
    }

}    





Modifier:

Ok j'essaye de décrire d'une autre manière ce que je veux réaliser. Je veux avoir plusieurs classes qui ont une méthode qui accepte un argument de ce type de classe. Donc, en plus de la classe A ci-dessus, disons qu'il y a une autre classe B qui ressemble à ceci:

public class B implements MyInterface {

    public void method(B object) {
       ...
    }

}

ce que les classes de stand A et B ont en commun est une méthode appelée "méthode" qui reçoit un argument du type de la classe elle-même.

Dans mon projet, je veux atteindre les objectifs suivants. Je suis en train d'écrire un petit jeu et je veux implémenter une sorte de détection de collision. en gros, je veux le faire en faisant des appels polymorphes "intelligents".

J'ai défini une interface ICollisionReceiver qui ressemble à ceci:

public interface ICollisionReceiver<T extends IShape> extends IShape {

    public boolean collides(T t);

}

et j'ai défini une autre interface comme celle-ci:

public interface ICollisionChecker<T extends ICollisionChecker<T>> extends IShape {

    public void addCollisionReceiver(ICollisionReceiver<T> receiver);

    public void removeCollisionReceiver(ICollisionReceiver<T> receiver);

}

Maintenant, par exemple, mon lecteur implémente l'interface ICollisionReceiver lorsque le joueur reçoit des collisions et les gère. Cela devrait être fait de manière générique, donc par exemple j'ai des boîtes et un cercle, maintenant le joueur implémente ICollisionReceiver <Box> et ICollisionReceiver <Circle> donc j'ai les deux méthodes

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

et

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

Dans ma classe de boîte et de cercle, je peux enregistrer ICollisionReceivers, puis je fais ce qui suit dans la méthode de mise à jour:

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

cela vérifie essentiellement si cette case entre en collision avec un certain récepteur, puis appelle la méthode collides () du récepteur.

Maintenant, le fait est que je veux m'assurer que les deux classes box et circle implémentent l'interface ICollisionChecker uniquement avec leur propre type.

Je peux explicitement le faire en faisant quelque chose comme ça

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

mais ce n'est pas très satisfaisant pour moi ...

Désolé pour le long post, j'espère que cela est clair.

21
zersaegen

Ce que vous voulez n'est pas possible en Java et n'est pas utile.

Donc, cela ne devrait pas être autorisé:

Pourquoi pas? À quoi cela sert-il? Les génériques ne sont pas à vous de faire des restrictions arbitraires. Les génériques ne sont utiles que pour éliminer les lancers dont vous auriez autrement besoin, car ils peuvent prouver que le lancer est toujours sûr.

Aussi longtemps que public class A implements MyInterface<B> est de type sécurisé, il est inutile de faire une restriction arbitraire qui l'interdit.

Vous devez simplement définir votre interface comme

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

et vous pouvez définir votre classe

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

et si quelqu'un d'autre définit une classe

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

alors qu'il en soit ainsi. Pourquoi t'en préoccupes-tu? Quel problème cela provoque-t-il?

28
newacct

Eh bien, c'est au moins possible:

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

Comme vous pouvez le voir, la déclaration générique ressemble un peu à une récursion infinie et je suis assez sûr que si Java n'a pas a un type d'effacement, ce serait - heureusement (?) tous les génériques sont en fait Objects après que le compilateur les a traités afin que vous puissiez le faire

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

et comme prévu, ce

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

imprime

Hello!
5
Esko