130 votes

Quelle est la différence entre ? et Objet dans les génériques Java ?

J'utilise Eclipse pour m'aider à nettoyer du code afin d'utiliser correctement les génériques Java. La plupart du temps, il fait un excellent travail d'inférence des types, mais il y a des cas où le type inféré doit être aussi générique que possible : Object. Mais Eclipse semble me donner la possibilité de choisir entre un type Object et un type ' ?

Alors quelle est la différence entre :

HashMap<String, ?> hash1;

y

HashMap<String, Object> hash2;

139voto

Johannes Weiß Points 19013

Une instance de HashMap<String, String> correspond à Map<String, ?> mais pas Map<String, Object> . Disons que vous voulez écrire une méthode qui accepte les cartes de String à quoi que ce soit : si vous écrivez

public void foobar(Map<String, Object> ms) {
    ...
}

vous ne pouvez pas fournir un HashMap<String, String> . Si vous écrivez

public void foobar(Map<String, ?> ms) {
    ...
}

ça marche !

Une chose parfois mal comprise dans les génériques de Java est que List<String> n'est pas un sous-type de List<Object> . (Mais String[] est en fait un sous-type de Object[] C'est l'une des raisons pour lesquelles les génériques et les tableaux ne font pas bon ménage. (les tableaux en Java sont covariants, les generics ne le sont pas, ils sont invariant )).

Un échantillon : Si vous souhaitez écrire une méthode qui accepte List s de InputStream et les sous-types de InputStream vous écrivez

public void foobar(List<? extends InputStream> ms) {
    ...
}

Au fait : Java efficace de Joshua Bloch est une excellente ressource lorsque vous souhaitez comprendre les choses pas si simples en Java. (Votre question ci-dessus est également très bien couverte dans le livre).

33voto

Julien Chastang Points 8357

Une autre façon de penser à ce problème est que

HashMap<String, ?> hash1;

est équivalent à

HashMap<String, ? extends Object> hash1;

Combinez ces connaissances avec le "principe du Get and Put" de la section (2.4) de Génériques et collections Java :

Le principe Get and Put : utilisez un étend le caractère générique lorsque vous ne récupérez que des valeurs d'une structure, utilisez un joker super lorsque vous ne mettez que des valeurs dans dans une structure, et n'utilisez pas de caractère générique lorsque vous obtenez et mettez à la fois des valeurs.

et la carte sauvage pourrait commencer à avoir plus de sens, avec un peu de chance.

11voto

topchef Points 7473

C'est facile à comprendre si vous vous rappelez que Collection<Object> est juste une collection générique qui contient des objets de type Object mais Collection<?> est un super type de tous les types de collections.

6voto

Eyal Points 2552

Les réponses concernant la covariance couvrent la plupart des cas mais omettent une chose :

" ?" est inclus dans "Object" dans la hiérarchie des classes. On pourrait dire que String est un type d'Object et que Object est un type de ?. Tout ne correspond pas à Object, mais tout correspond à ?.

int test1(List<?> l) {
  return l.size();
}

int test2(List<Object> l) {
  return l.size();
}

List<?> l1 = Lists.newArrayList();
List<Object> l2 = Lists.newArrayList();
test1(l1);  // compiles because any list will work
test1(l2);  // compiles because any list will work
test2(l1);  // fails because a ? might not be an Object
test2(l2);  // compiled because Object matches Object

4voto

erickson Points 127945

Vous ne pouvez pas mettre en sécurité n'importe quoi dans Map<String, ?> parce que vous ne savez pas de quel type les valeurs sont censées être.

Vous pouvez placer n'importe quel objet dans un Map<String, Object> parce que la valeur est connue pour être un Object .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X