Почему абстрактная реализация возвращается Map.values ​​()? - PullRequest
3 голосов
/ 19 июня 2019
Map<Integer, String> map = new TreeMap<>();
map.put(1, "String1");
map.put(2, "String2");
map.put(3, "String3");

Я хотел преобразовать значения map, чтобы установить. Я знаю, я мог бы легко сделать

Set<String> set = new HashSet<>(map.values());

Размышляя об этом, мне было любопытно, что же такое "1006" само по себе? Итак, я попробовал это

System.out.println("Set:"+ (map.values() instanceof Set));      
System.out.println("List:"+ (map.values() instanceof List));    
System.out.println("Queue:"+ (map.values() instanceof Queue));
System.out.println("SortedSet:"+ (map.values() instanceof SortedSet));

И на удивление был

Set:false
List:false
Queue:false
SortedSet:false

Это - все, что сказано в документации.

представление коллекции значений, содержащихся в этой карте

Затем я посмотрел на декомпилированный файл класса.

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

Почему Java возвращает абстрактную реализацию вместо List / Set / Queue, которая может быть немедленно совместима с вариантами использования?

Ответы [ 3 ]

5 голосов
/ 19 июня 2019

Я не знаю, какую версию Java вы используете, но я не вижу экземпляр абстрактного класса, возвращаемый values(). Он возвращает экземпляр TreeMap.Values, который является классом, расширяющим AbstractCollection.

Относительно того, почему он не возвращает Set - это просто из-за того факта, что коллекция значений может содержать дубликаты, которые Set не допускает.

A List также не идеален, поскольку подразумевает, что значения упорядочены, что не верно для всех реализаций Map (таких как HashMap).

Кстати, вместо того, чтобы печатать такие вещи, как map.values() instanceof Set, вы могли бы просто напечатать map.value().getClass().getName(), чтобы увидеть фактический класс реализации.

3 голосов
/ 19 июня 2019

При рассмотрении реализации есть одна причина: contains и iterator оба смотрят на текущее содержимое карты, а не на содержимое карты при вызове values().

Если вы позвоните values() и затем измените что-то на карте, это изменение будет отражено в Collection, первоначально возвращенном из 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
1 голос
/ 19 июня 2019

Hashset внутренне использует HashMap, поэтому в сценарии не так много копий значений.

Вы можете увидеть соответствующую ссылку, чтобы получить больше об этом. Ссылка на ссылку .

где находится сборник тезисов. Ниже приведена некоторая сопутствующая информация, полученная из Java Doc:

1] Этот класс предоставляет скелетную реализацию коллекции. интерфейс, чтобы минимизировать усилия, необходимые для реализации этого интерфейса.

2] Для реализации неизменяемой коллекции программисту нужно только расширить этот класс и обеспечить реализации для <tt>iterator</tt> и <tt>size</tt> методы. (Итератор, возвращаемый <tt>iterator</tt> метод должен реализовывать <tt>hasNext</tt> и <tt>next</tt>.

3] Для реализации модифицируемой коллекции, программист должен дополнительно переопределить этот class's <tt>add</tt> метод (который в противном случае выдает UnsupportedOperationException), итератор, возвращенный Метод итератора должен дополнительно реализовать его remove Метод. * * тысяча двадцать-один

Надеюсь, это было полезно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...