Подтвердить что ты не робот

Почему у java.util.HashSet нет метода get (Object o)?

Я видел другие вопросы о получении объектов из Set на основе значения индекса, и я понимаю, почему это невозможно. Но я не смог найти хорошее объяснение того, почему нельзя получить объект по объекту, поэтому я думал, что спрошу.

HashSet поддерживается HashMap, поэтому получение объекта из него должно быть довольно простым. Как и сейчас, кажется, мне придется перебирать каждый элемент в HashSet и проверять равенство, которое кажется ненужным.

Я мог бы просто использовать HashMap, но мне не нужна пара ключ: значение, мне просто нужен Set.

Например, у меня есть Foo.java:

package example;

import java.io.Serializable;

public class Foo implements Serializable {

    String _id;
    String _description;

    public Foo(String id){
        this._id = id
    }

    public void setDescription(String description){
        this._description = description;
    }

    public String getDescription(){
        return this._description;
    }

    public boolean equals(Object obj) {
        //equals code, checks if id are equal
    }

    public int hashCode() {
        //hash code calculation
    }

}

и Example.java:

package example;

import java.util.HashSet;

public class Example {

    public static void main(String[] args){
        HashSet<Foo> set = new HashSet<Foo>();

        Foo foo1 = new Foo("1");
        foo1.setDescription("Number 1");

        set.add(foo1);
        set.add(new Foo("2"));

        //I want to get the object stored in the Set, so I construct a object that is 'equal' to the one I want.
        Foo theFoo = set.get(new Foo("1")); //Is there a reason this is not allowed?
        System.out.println(theFoo.getDescription); //Should print Number 1
    }

}

Это потому, что метод equals предназначен для проверки "абсолютного" равенства, а не "логического" равенства (в этом случае будет достаточно (Object o))?

4b9b3361

Ответ 1

Набор представляет собой набор объектов, который рассматривает a.equals(b) == true как дубликаты, поэтому нет смысла пытаться получить тот же самый объект, который у вас уже есть.

Если вы пытаетесь получить (объект) из коллекции, скорее всего, будет более подходящей Карта.

Что вы должны написать:

Map<String, String> map = new LinkedHashMap<>();

map.put("1", "Number 1");
map.put("2", null);
String description = set.get("1");

Если объект не находится в наборе (на основе равно), добавьте его, если он находится в наборе (на основе equals), дайте мне экземпляр набора этого объекта

В маловероятном случае вам это понадобится, вы можете использовать карту.

Map<Bar, Bar> map = // LinkedHashMap or ConcurrentHashMap

Bar bar1 = new Bar(1);
map.put(bar1, bar1);

Bar bar1a = map.get(new Bar(1));

Ответ 2

Карта карты/сборка карт Java

Будет ли он содержать пару ключ/значение или значения только?

1) Если он содержит пары, выбор является отображением. Важен ли порядок?

. 1-1) Если да, выполните порядок вставки или отсортируйте по клавишам?

., 1-1-1) Если упорядочено, LinkedHashMap

., 1-1-2) Если отсортировано, TreeMap

. 1-2) Если порядок не важен, HashMap

2) Если в нем хранятся только значения, выбор - это коллекция. Будет ли он содержать дубликаты?

. 2-1) Если да, ArrayList

. 2-2) Если он не будет содержать дубликатов, основной задачей является поиск элементов (Содержит/удалить)?

., 2-2-1) Если нет, ArrayList

., 2-2-2) Если да, важно ли порядок?

., 2-2-2-1) Если порядок не важен, HashSet

., 2-2-2-2) Если да, выполните порядок вставки или отсортируйте по значениям?

.,, 2-2-2-2-1), если упорядочено, LinkedHashSet

.,, 2-2-2-2-2), если отсортировано, TreeSet

Ответ 3

Последнее предложение - ответ.

get(Object o) будет выполняться через HashSet, ища другой объект, равный o (используя метод equals(o)). Таким образом, это действительно то же самое, что и contains(o), но не возвращает тот же результат.

Ответ 4

Если вы хотите знать, что объект new Foo("1"); уже присутствует в set, тогда вам нужно использовать метод contains как:

boolean present =  set.contains(new Foo("1"));

Метод get типа i.e set.get(new Foo("1")); не поддерживается, потому что это не имеет смысла. У вас уже есть объект, т.е. new Foo("1"), а затем какую дополнительную информацию вы просматриваете с помощью метода get.

Ответ 5

HashSet немного проще, чем HashMap. Если вам не нужны функции HashMap, зачем использовать его? Если метод, подобный getObject (ObjectType o), был реализован Java, нам не нужно перебирать множество после вызова метода contains()...

Ответ 6

Причина, почему нет, проста:

Если вам нужно получить объект X из набора, это потому, что вам нужно что-то из X, и у вас нет объекта.

Если у вас нет объекта, вам нужно какое-то средство (ключ), чтобы найти его... имя, число, что когда-либо. То, что карты для правильного.

map.get( "ключ" ) → X!

У наборов нет ключей, вам нужно пройти их, чтобы получить объекты.

Итак, почему бы не добавить удобный get (X) → X

Это не имеет никакого смысла, потому что у вас уже есть X, говорит пурист.

Но теперь посмотрите на него как на не пуриста и посмотрите, действительно ли вы этого хотите:

Скажем, я делаю объект Y, совпадающий с равными X, так что set.get(Y) → X. Воля, тогда я могу получить доступ к данным X, которые у меня не было. Скажем, например, у X есть метод под названием get flag(), и я хочу получить результат.

Теперь посмотрите на этот код.

У

X = map.get(Y);

Итак, Y.equals(x) true!

а..

Y.flag() == X.flag() = false. (Не были ли они равны?)

Итак, вы видите, если set позволил вам получить объекты, подобные этому. Это, безусловно, должно сломать основную семантику равных. Позже вы собираетесь жить с маленькими клонами X, все обвиняют в том, что они такие же, когда они не являются.

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

Ответ 7

Общим вариантом использования метода get на Set может быть реализация интернального набора. Если это то, чего вы пытаетесь достичь, рассмотрите возможность использования Interner интерфейса и Interners factory от Google Guava.

Ответ 8

Здесь быстрый способ перебора через Hashset -

Set<Integer> integerSet=new HashSet<Integer>();
integerSet.add(4);
integerSet.add(1);
integerSet.add(4);
integerSet.add(45);
integerSet.add(2);

for (Object anIntegerSet : integerSet)
     System.out.println(anIntegerSet);

Ответ 9

если вы хотите знать только то, что находится в Hashset, вы можете использовать метод .toString(); для отображения всего содержимого Hashset, разделенного запятой.

Ответ 10

Мы хотим иметь доступ к элементу напрямую через его значение ключа вместо того, чтобы определять свое местоположение сначала, ища значение ключа в массиве. (Вот почему интерфейс Set имеет метод contains(obj) вместо get(index).)

Структуры данных: абстракция и дизайн с использованием Java, Koffman

Ответ 11

Как упоминалось ранее, такого метода и по уважительным причинам нет. При этом, если вы хотите получить определенный объект из HashSet в java 8, используя однострочный (почти), просто используйте потоки. В вашем случае это будет что-то вроде:

Foo existing = set.stream().filter(o -> o.equals(new Foo("1"))).collect(Collectors.toList()).iterator().next();

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