2013-06-07 2 views
0
class Foo 
{ 
    int x; 
    int y; 
    int z; 

    //Overriding equals() and hashCode() to just field x 
} 

List<Foo> myList=new ArrayList<Foo>(); 

myList.add(fooObj); 
myList.add(fooObj2); 

Все мои Foo Объекты в основном сравниваются на основе поля x.Как вернуть объект из коллекции.

Я хотел бы получить fooObj из списка по значению x. Почему нет смысла добавлять метод get(Object o) вместо работы вокруг list.get(list.indexOf(fooObj)), чтобы получить полный объект из списка. indexOf() может возвращать «null« так что нужна нулевая проверка, которая также не хороша.

UPDATE:

Карта будет хорошей идеей иметь ключевое значение пары GetX() -> objFoo. Если мой Foo определяется двумя полями, скажем, X и Y класса Foo, то Карта не может использоваться для этой цели.

+0

Если вы хотите получить объекты таким образом (в основном, используя частичные экземпляры Foo как ключей для извлечения сохраненных экземпляров), вам, вероятно, рекомендуется рассмотреть возможность поиска в виде набора ключей, например 'Set ' – CPerkins

+0

Набор тем хуже. Вы даже не можете получить такой объект, как список путей, который можно выполнить с помощью метода IndexOf(), а затем применить get(). –

+1

Почему вы не могли создать парный объект, содержащий y и z, и сохранить его на карте? – selig

ответ

1

Вы могли бы использовать вместо Map<Foo, Foo>:

Map<Foo, Foo> map = new HashMap<Foo, Foo>(); 
// Store 
map.put(fooObj, fooObj); 
// Retrieve 
map.get(fooObj2); // => fooObj 

Хотя я думаю, что переопределение equals не очень хорошее решение для этого случая использования. Ваш equals override обрабатывает fooObj и fooObj2 как «равные», но ваше приложение хочет, чтобы в каком-то месте их рассматривали как разные. Эти конфликты рано или поздно возвращаются, вводят ошибки и дают вам головные боли.

Я предпочел бы отделить идентификатор от данных и дать Foo a FooKey.

class FooKey { 
    final int x; 

    public FooKey(int x) { 
     this.x = x; 
    } 

    // TODO Override equals and hashCode to only compare FooKeys on x field 
} 

class Foo { 
    final FooKey id; 
    int y; 
    int z; 

    public Foo(FooKey id) { 
     this.id = id; 
    } 
} 

Ваш код приложения становится гораздо легче понять:

Map<FooKey, Foo> map = new ArrayList<FooKey, Foo>(); 
// Store 
Foo fooObj = new Foo(new FooKey(123)); 
map.put(fooObj.id, fooObj); 
// Retrieve 
map.get(fooObj.id); // => fooObj 
map.get(new FooKey(123)); // also fooObj if FooKey.equals is properly overridden 

Использование отдельного (композитный) ключевое поле также может оказаться полезной, когда вы решили, что хотите сохраняться ваши Foo объекты в базе данных. Например, JPA позволяет использовать @IdClass или @EmbeddedId, чтобы Foo объекты были идентифицированы FooKey s. Возможно, это не относится к вашему текущему сценарию, но если вы подумываете о реализации настойчивости в будущем, вы, вероятно, захотите начать рассмотрение этого вопроса в своей иерархии классов.

+0

спасибо за решение. Я чувствую, что Java API должен был включать такие вещи в свои реализации List. –

+1

@JavaEnthusiast Это не работа «Список», и, на мой взгляд, ни один класс не должен этого делать. Если вы скажете: 'fooObj.equals (fooObj2)' истинно, если 'fooObj.x == fooObj2.x', то вы * должны ожидать, что * другие классы будут обрабатывать их * как равные *. Многие классы полагаются на это, и если вы попытаетесь навязать свои собственные правила, нет никакой гарантии, что все будет работать так, как ожидалось. –

0

list.get(list.indexOf(fooObj)) не является обходным путем, это именно то, как разработан класс List. You может добавить get (Object), если вы хотите, наследуя от класса List, добавляя этот метод и используя ваш новый тип вместо List. Но для такой небольшой выгоды это похоже на большую работу.

+0

Можете ли вы порекомендовать Каков наилучший способ получить элемент из списка в этой ситуации? –

+0

Да, точно так, как вы это делали. Используйте indexOf, а затем используйте get (index). – KyleM

+0

Yup. Нужно делать нулевую проверку каждый раз. :( –

Смежные вопросы