3
votes

Pourquoi l'implémentation abstraite est retournée par Map.values ​​()?

public Collection<V> values() {
    if (values == null) {
        values = new AbstractCollection<V>() {
            public Iterator<V> iterator() {
                return new Iterator<V>() {
                    private Iterator<Entry<K,V>> i = entrySet().iterator();

                    public boolean hasNext() {
                        return i.hasNext();
                    }

                    public V next() {
                        return i.next().getValue();
                    }

                    public void remove() {
                        i.remove();
                    }
                };
            }

            public int size() {
                return AbstractMap.this.size();
            }

            public boolean isEmpty() {
                return AbstractMap.this.isEmpty();
            }

            public void clear() {
                AbstractMap.this.clear();
            }

            public boolean contains(Object v) {
                return AbstractMap.this.containsValue(v);
            }
        };
    }
    return values;
}

1 commentaires

De cette façon, la représentation interne est rendue accessible sans avoir à copier la carte / l'ensemble dans une nouvelle collection ou à vous rendre dépendant des détails d'implémentation.


3 Réponses :


5
votes

Je ne sais pas quelle version de Java vous utilisez, mais je ne vois pas d'instance de classe abstraite renvoyée par values ​​() . Il renvoie une instance de TreeMap.Values ​​, qui est une classe qui étend AbstractCollection .

Quant à savoir pourquoi il ne renvoie pas un Set - c'est simplement dû au fait que la collection de valeurs peut contenir des doublons, ce qu'un Set ne permet pas .

Une Liste n'est pas non plus idéale, car elle impliquerait que les valeurs sont ordonnées, ce qui n'est pas vrai pour toutes les implémentations de Map (telles que HashMap ).

BTW, au lieu d'imprimer des choses comme map.values ​​() instanceof Set , vous auriez pu simplement imprimer map.value (). getClass (). getName () pour voir la classe d'implémentation réelle.


1 commentaires

Cela vient de java8 .



3
votes

Une raison simplement en regardant l'implémentation: contains et iterator regardent tous les deux le contenu actuel de la carte par opposition au contenu de la carte lorsque values ​​() a été appelée.

Si vous appelez values ​​() puis modifiez quelque chose dans la carte, ce changement sera reflété dans la Collection renvoyée à l'origine depuis values().

Map<String, String> map = new HashMap<String, String>();
map.put("some", "thing");
Collection<String> values = map.values();
System.out.println(values.size()); // 1
map.put("foo", "bar");
System.out.println(values.size()); // 2


0 commentaires

1
votes

Hashset utilise HashMap en interne, il n'y a donc pas beaucoup de copie des valeurs dans le scénario.

Vous pouvez voir le lien associé pour en savoir plus. Lien de référence .

d'où vient la collection abstraite, voici quelques informations connexes extraites de Java Doc:

1] Cette classe fournit une implémentation squelettique de la Collection interface, afin de minimiser l'effort requis pour implémenter cette interface.

2] Pour implémenter une collection non modifiable, le programmeur n'a qu'à étendre cette classe et fournir des implémentations pour le iterator et Méthodes size . (L'itérateur renvoyé par le iterator La méthode doit implémenter hasNext et next .

3] Pour implémenter une collection modifiable, le programmeur doit en plus écraser la méthode add de cette classe (qui UnsupportedOperationException ) et l'itérateur renvoyé par le La méthode iterator doit en plus implémenter son remove méthode.

J'espère que cela vous a été utile.


0 commentaires