2017-08-07 6 views
-1

J'ai déclaré une carte qui contient la cartographie des clés de type long à une Nested CarteImpossible de mettre l'objet dans une carte générique

emboîtées Maps a les clés de la classe Type et les valeurs de type SomeClient Fondamentalement, je suis en train de générer un mappage de type de classe vers les clients qui produisent la réponse du type de classe.

private static final Map<Long, Map<Class<? super GenericResponse>, SomeClient<? super GenericResponse>>> someClientMap 
     = new HashMap<Long, Map<Class<? super GenericResponse>, SomeClient<? super GenericResponse>>>(); // <? super GenericResponse> should enable me to put subclasses of type GenericResponse in the Map 

La méthode getSomeClient est une méthode générique qui accepte le type de classe comme argument et renvoie le client qui produit des réponses du type de classe (Le type de classe ne peut être une sous-classe de GenericResponse:. Avis paramètre de type dans la signature de la méthode)

public static <T extends GenericResponse> SomeClient<T> getSomeClient(long clientId,Class<T> clazz) throws IOException { 
    if (someClientMap.get(clientId) == null) { 
     synchronized (someClientMap) { 
      someClientMap.put(clientId, new HashMap<Class<T>,SomeClient<T>>()); //getting error here      
     } 
    } 
    return someClientMap.get(clientId); 
} 

le problème est que je reçois une erreur de compilation où je suis en train de mettre le client dans la carte.

L'erreur exacte est

The method put(Long, Map<Class<? super GenericResponse>,SomeClient<? super GenericResponse>>) in the type Map<Long,Map<Class<? super GenericResponse>,SomeClient<? super GenericResponse>>> is not applicable for the arguments (long, HashMap<Class<T>,SomeClient<T>>) 

J'éprouve des difficultés rappelant ce que je fais exactement je tort. S'il vous plaît aider.

Déclaration pour SomeClient est

public class SomeClient<T extends GenericResponse> 

et pour la contructor est

public SomeClient(Class<T> clazz) 
+0

On dirait que le problème est dans 'Long' vs' long' - vous mettez un argument 'long', map attend' Long'. Ajouter une conversion ou utiliser la méthode 'Long.valueOf (.)' –

+0

Pourriez-vous poster dans la question la déclaration de 'SomeClient' et' GenericResponse'? –

Répondre

0

Il y a plusieurs problèmes dans votre code. Tout d'abord, si vous voulez autoriser les sous-types, vous devez utiliser extends et non super:

private static final Map<Long, Map<Class<? extends GenericResponse>, SomeClient<? extends GenericResponse>>> someClientMap 
     = new HashMap<Long, Map<Class<? extends GenericResponse>, SomeClient<? extends GenericResponse>>>(); 

Cela dit que vous autorisez les sous-types de GenericResponse comme paramètre générique de Class et SomeClient dans le Map, mais il ne vous permet pas pour utiliser des sous-types de Class (même pour SomeClient) lui-même, et pour tout ce que nous connaissons Class<T> (où T extends GenericResponse) est un sous-type de Class<? extends GenericResponse>, comme le premier est une "spécialisation" de ce dernier pour un T spécifique.

En utilisant cette définition, vous devez garder les mêmes paramètres génériques de la Map intérieure en le mettant dans l'extérieur un:

someClientMap.put(clientId, new HashMap<Class<? extends GenericResponse>, SomeClient<? extends GenericResponse>>()); 

Vous pouvez garder le put comme vous l'avez bien, si vous ajoutez un peu plus extends à la déclaration initiale pour permettre les sous-types de Class et SomeClient:

private static final Map<Long, Map<? extends Class<? extends GenericResponse>, ? extends SomeClient<? extends GenericResponse>>> someClientMap 
     = new HashMap<Long, Map<? extends Class<? extends GenericResponse>, ? extends SomeClient<? extends GenericResponse>>>(); 

et vous pouvez juste faire:

someClientMap.put(clientId, new HashMap<Class<T>, SomeClient<T>>()); 

De toute façon, vous ne serez pas vous éloigner de moulages laides lors de l'accès someClientMap:

return (SomeClient<T>) someClientMap.get(clientId).get(clazz); 
+0

Merci pour la réponse, mais j'ai utilisé super au lieu de s'étendre parce que je veux ajouter différentes sous-classes de la classe GenericType à la même carte. S'il vous plaît se référer à cette question https://stackoverflow.com/questions/4343202/difference-between-super-t-and-extends-t-in-java pour une explication. –

+0

@ rohit.agrawal Avez-vous lu les réponses à cette question? C'est assez simple: si vous voulez autoriser les ** sous-classes ** de GenericType, utilisez '? extends GenericType'; si vous voulez autoriser ** superclasses ** de GenericType utiliser '? super GenericType'. –

+0

Je ne veux pas seulement autoriser une sous-classe de GenericType dans la carte, je veux autoriser plusieurs sous-types dans la même carte. Copier quelques parties de la réponse dans le lien ici pour souligner ce que je dis. Si une liste est déclarée comme 'List foo3'; Vous ne pouvez pas ajouter un entier parce que foo3 pourrait pointer sur une liste . Vous ne pouvez pas ajouter de doublon car foo3 peut pointer sur une liste . Vous ne pouvez pas ajouter de numéro car foo3 peut pointer sur une liste . –

0

L'erreur est due au fait que Java génériques sont invariant, à savoirbien que String est un sous-type de Object la ligne suivante ne parviendra pas à compiler:

Map<Long, Object> map = new HashMap<Long, String>(); 

parce Map<Long, String> n'est pas un sous-type de Map<Long, Object>.

Mais nous pouvons surmonter cette restriction en utilisant wildcards bornées, à savoir

Map<Long, ? extends Object> map = new HashMap<Long, String>(); 

Ce pourquoi il y a un Class<? super GenericResponse> dans votre code, mais vous vous êtes arrêté à mi-chemin. Vous devriez avoir utilisé la même technique dans le niveau supérieur, à savoir écrire:

Map<Long, Map<? extends Class<? extends GenericResponse>, ? extends SomeClient<? extends GenericResponse>>> 

au lieu de

Map<Long, Map<Class<? extends GenericResponse>, SomeClient<? extends GenericResponse>>> 

Par la façon dont je l'ai remplacé ? super avec ? extends dans mon exemple parce que je vous pense don ne les utilisez pas correctement.

-1

J'ai trouvé le problème. Dans l'instruction ci-dessous

someClientMap.put(clientId, new HashMap<Class<T>,SomeClient<T>>()); 

La nouvelle HashMap que je crée est plus restrictive que ce que la carte externe accepte. puisque T étend GenericResponse à la méthode générique.

La déclaration permet de différentes sous-classes de la classe GenericResponse être stockés dans la même carte, depuis que je suis en utilisant super

private static final Map<Long, Map<Class<? super GenericResponse>, SomeClient<? super GenericResponse>>> someClientMap 
    = new HashMap<Long, Map<Class<? super GenericResponse>, SomeClient<? super GenericResponse>>>(); // <? super GenericResponse> should enable me to put subclasses of type GenericResponse in the Map 

S'il vous plaît se référer Difference between <? super T> and <? extends T> in Java pour une très bonne explication du même.

Pour résoudre le problème, j'ai remplacé la déclaration de vente à

someClientMap.put(clientId, new HashMap<Class<? super GenericResponse>,SomeClient<? super GenericResponse>>()); 

Cette vente garantit que la carte intérieure peut en effet contenir des instances de différentes sous-classes de la classe GenericResponse comme cela a été déclaré dans la déclaration initiale.

private static final Map<Long, Map<Class<? super GenericResponse>, SomeClient<? super GenericResponse>>> someClientMap 
    = new HashMap<Long, Map<Class<? super GenericResponse>, SomeClient<? super GenericResponse>>>(); 
+0

Vous utilisez '? super GenericResponse' mais dans le texte, vous dites que vous devez "tenir des instances de sous-classes ** différentes ** de la classe' GenericResponse' "- ceci est déroutant, soit utiliser'? super GenericResponse' et dites "superclasses de la classe' GenericResponse' "ou utilisez'? étend GenericResponse' et dit "sous-classes de la classe' GenericResponse' " –

+0

lorsque j'utilise et dit "tenir des instances de différentes sous-classes de la classe GenericResponse" je le pense. C'est un peu contre-intuitif mais c'est comme ça. S'il vous plaît se référer à la réponse acceptée pour https://stackoverflow.com/questions/4343202/difference-between-super-t-and-extends-t-in-java pour une très bonne explication de la même chose. –

+0

Vous avez raison, merci pour le lien –