web-dev-qa-db-fra.com

Passer la classe d'interface en tant que paramètre dans Java

J'ai une interface:

public interface IMech {

}

et une classe qui le met en œuvre

public class Email implements IMech {

}

et une troisième classe qui a implémenté cette méthode:

public void sendNotification( Class< IMech > mechanism ){
}

maintenant j'essaie d'appeler cette méthode comme ça

foo.sendNotification(Email.class);

mais je reçois toujours une exception disant:

The method sendNotification(Class<IMech>) in the type RemediationOperator is not applicable for the arguments (Class<Email>)

Cela ne devrait-il pas fonctionner s'il interface cette classe?

33
aleclerc

Peut-être avez-vous besoin

public void sendNotification( Class<? extends IMech> mechanism ) { 
48
axtavt

Parce que les deux classes Class<IMechanism> Et Class<EmailNotification> Elles-mêmes sont pas liées par héritage, même si IMechanism et EmailNotificationsont.

Vous devez obliger votre méthode à accepter un Class<? extends IMechanism>.

10
Mike Daniels

Votre mécanisme de paramètres doit utiliser un caractère générique borné, comme ceci:

public void sendNotification (mécanisme de classe <? étend IMech>) {}

Citant le didacticiel sur les génériques texte du lien

En général, si Foo est un sous-type (sous-classe ou sous-interface) de Bar, et G est une déclaration de type générique, ce n'est pas le cas que G est un sous-type de G.

5
rwhit

la bonne façon est:

public void sendNotification(IMech mechanism) {

}

alors s'il vous plaît lire quelques tutoriels Java sur les interfaces tout le monde!

3
chandler newman

Les génériques ne fonctionnent pas de cette façon en Java. Ce dont vous avez vraiment besoin pour changer la signature de la méthode en

public void sendNotification( Class< ? extends IMech > mechanism ){
}

Ou est-ce que super au lieu de extends... permettez-moi de consulter Effective Java's chapitre Génériques ...

Edit: Effective Java dit:

Voici un mnémonique pour vous aider à vous souvenir du type de caractère générique à utiliser: PECS signifie producteur-étendues, consommateur-super.

Je suppose que cela produira des instances IMech et que extends est correct.

3
Powerlord

OMI, il serait plus propre si vous faites ceci:

public void sendNotification( IMech mechanism ){
}

Vous pouvez toujours obtenir la classe à l'intérieur de la méthode.

1
fastcodejava

L'idée derrière les interfaces est que vous n'avez pas besoin de savoir de laquelle il s'agit. Vous devriez simplement être en mesure de transmettre un IMech et d'appeler sa fonctionnalité indépendamment de l'implémentation. Considérer ce qui suit:

public interface IMech {
    void sendMessage();
}

public class Email implements IMech {
    @Override
    void sendMessage() { /* stuff here to send email */ }
}

C'est le modèle d'utilisation typique d'une interface. Si vous ne l'utilisez que pour une option, vous devriez peut-être envisager d'utiliser plutôt une énumération.

enum IMech { EMAIL, INSTANT_MESSAGE, SNAIL_MAIL, YELL_OVER_CUBICLE }

public void sendNotification( IMech mechanism ){
    switch(mechanism) {
        case IMech.EMAIL: // do email .. etc
    }
}

foo.sendNotification(IMech.EMAIL);

Maintenant, je sais que ceux-ci ne répondent pas directement à vos questions, mais ce sont les formes d'utilisation typiques, et sont généralement indicatives de modèles de conception plus adaptables. Après tout, avez-vous vraiment besoin d'envoyer un objet de classe? Une énumération semble plus appropriée si vous déterminez simplement quel mécanisme utiliser.

1
corsiKa