【问题标题】:Get specific objects from ArrayList when objects were added anonymously?匿名添加对象时从 ArrayList 获取特定对象?
【发布时间】:2013-08-29 15:43:07
【问题描述】:

我已经为我的问题创建了一个简短的示例。我正在匿名创建对象列表并将它们添加到ArrayList。一旦项目在ArrayList 中,我稍后会回来并为列表中的每个对象添加更多信息。如果您不知道其索引,有没有办法从列表中提取特定对象?

我只知道对象的“名称”,但你不能做list.get(ObjectName) 或任何事情。处理此问题的推荐方法是什么?每次我想检索一个特定对象时,我都不想遍历整个列表。

public class TestCode{

    public static void main (String args []) {
        Cave cave = new Cave();

        // Loop adds several Parties to the cave's party list
        cave.parties.add(new Party("FirstParty")); // all anonymously added
        cave.parties.add(new Party("SecondParty"));
        cave.parties.add(new Party("ThirdParty"));

        // How do I go about setting the 'index' value of SecondParty for example?
    }
}

class Cave {
    ArrayList<Party> parties = new ArrayList<Party>();
}

class Party extends CaveElement{
    int index;

    public Party(String n){
        name = n;
    }

   // getter and setter methods 

    public String toString () {
        return name;
    }
}


class CaveElement {
    String name = "";
    int index = 0;

    public String toString () {
        return name + "" + index;
    }
}

【问题讨论】:

  • 你必须使用列表吗?

标签: java object arraylist


【解决方案1】:

List.indexOf() 会给你你想要的,只要你知道你在做什么,如果Partyequals() 方法是明确定义的。

Party searchCandidate = new Party("FirstParty");
int index = cave.parties.indexOf(searchCandidate);

这就是有趣的地方 - 子类不应该检查其父类的私有属性,因此我们将在超类中定义 equals()

@Override
public boolean equals(Object o) {
    if (this == o) {
        return true;
    }
    if (!(o instanceof CaveElement)) {
        return false;
    }

    CaveElement that = (CaveElement) o;

    if (index != that.index) {
        return false;
    }
    if (name != null ? !name.equals(that.name) : that.name != null) {
        return false;
    }

    return true;
}

如果您覆盖 equals,则覆盖 hashCode 也是明智之举 - hashCode 的一般合同规定,如果 x.equals(y),则 x.hashCode() == y.hashCode()

@Override
public int hashCode() {
    int result = name != null ? name.hashCode() : 0;
    result = 31 * result + index;
    return result;
}

【讨论】:

    【解决方案2】:

    如果您想根据对象的String 名称查找对象,这是Map 的教科书案例,例如HashMap。您可以使用 LinkedHashMap 并稍后将其转换为 ListArray(Chris 在下面的 cmets 中很好地介绍了这一点)。

    LinkedHashMap 因为它允许您按照插入顺序访问元素(如果您愿意的话)。否则HashMapTreeMap 可以。

    您可以按照其他人的建议将其与 List 一起使用,但这对我来说感觉很糟糕......从短期和长期来看,这都会更干净。

    如果您必须为对象使用列表,您仍然可以将对象名称的Map 存储到数组的索引中。这有点难看,但你得到的性能几乎和普通的Map 一样。

    【讨论】:

    • 特别是,您始终可以使用map.values().toArray(new Party[0]) 转储到数组中,也可以使用new ArrayList&lt;Party&gt;(map.values()) 转储到列表中。
    • 到目前为止,在所有 5 或 6 个答案中,我最喜欢你的一个。它具有 O(1) 查找并且仍然保持插入顺序。
    • @ChrisJester-Young 是的,谢谢,这就是为什么我建议LinkedHashMap,我应该明确说明
    • 我只能接受一个答案,我也喜欢这个答案。不幸的是,由于我项目的性质,我有点卡在列表中,所以我选择了另一个答案。你仍然会得到赞成票。
    • @leigero 很好,你接受对你有意义的事情。感谢您的+1。请考虑一下我最后建议的混合解决方案。
    【解决方案3】:

    我建议覆盖Party 类的equals(Object)。它可能看起来像这样:

    public boolean equals(Object o){
        if(o == null)
            return false;
        if(o instanceof String)
            return name.equalsIgnoreCase((String)o);
        else if(o instanceof Party)
            return equals(((Party)o).name);
        return false;
    }
    

    完成后,您可以使用indexOf(Object)方法来检索其名称指定的一方的索引,如下所示:

    int index = cave.parties.indexOf("SecondParty");
    

    将返回名称为 SecondPartyParty 的索引。

    注意:这仅在您覆盖 equals(Object) 方法时才有效。

    【讨论】:

    • 我还建议它违反equals 合同,但这只是 MHO :P
    • @MadProgrammer 嗯,虽然看起来很方便:P
    • 也许很方便,但是如果你有两个 Party 对象名称相同,但索引不同,会发生什么情况。合同现在已经违约了;)
    • 是的,从来没有考虑过:(
    【解决方案4】:

    老实说,您可以使用 list.indexOf(Object) 错误,您所描述的听起来您最好使用 Map

    试试这个:

    Map<String, Object> mapOfObjects = new HashMap<String, Object>();
    mapOfObjects.put("objectName", object);
    

    然后当你想检索对象时,使用

    mapOfObjects.get("objectName");
    

    假设您确实知道您所说的对象的名称,这将更简洁,并且性能更快,特别是如果地图包含大量对象。

    如果需要Map中的对象保持有序,可以使用

    Map<String, Object> mapOfObjects = new LinkedHashMap<String, Object>();
    

    改为

    【讨论】:

      【解决方案5】:

      鉴于List 的使用,没有迭代就无法“查找”一个值...

      例如...

      Cave cave = new Cave();
      
      // Loop adds several Parties to the cave's party list
      cave.parties.add(new Party("FirstParty")); // all anonymously added
      cave.parties.add(new Party("SecondParty"));
      cave.parties.add(new Party("ThirdParty"));
      
      for (Party p : cave.parties) {
          if (p.name.equals("SecondParty") {
              p.index = ...;
              break;
          }
      }
      

      现在,这需要时间。如果您要查找的元素位于列表末尾,则必须在找到匹配项之前迭​​代到列表末尾。

      使用某种Map 可能会更好...

      所以,如果我们将Cave 更新为...

      class Cave {
          Map<String, Party> parties = new HashMap<String, Party>(25);
      }
      

      我们可以做类似...

      Cave cave = new Cave();
      
      // Loop adds several Parties to the cave's party list
      cave.parties.put("FirstParty", new Party("FirstParty")); // all anonymously added
      cave.parties.put("SecondParty", new Party("SecondParty"));
      cave.parties.put("ThirdParty", new Party("ThirdParty"));
      
      if (cave.parties.containsKey("SecondParty")) {
          cave.parties.get("SecondParty").index = ...
      }
      

      相反...

      最终,这一切都取决于您想要实现的目标......

      【讨论】:

      • 我相信这是最有帮助的回应。我将无法使用地图,为了建立 SSCCE,这个谜题比我在这个问题中包含的更多。谢谢你的回答。
      • @leigero 如果你想要两全其美,你可以使用HashMap 来存储name 的映射 -> 索引..
      • 即使您出于其他原因需要 List 的功能,您最好还是在后台将其作为 LinkedHashMap 运行并根据需要将其转换为 List。地图效率更高
      • @leigero 如果对ArrayList 进行了排序,您可以使用很多技巧,但这可能超出您的要求;)
      • @StormeHawke 假设 OP 不需要对List 进行 randmon 访问。仍然是一个有效的观点;)
      【解决方案6】:

      根据您的问题要求,我想建议 Map 将非常高效且轻松地解决您的问题。

      在 Map 中,您可以将名称作为键,将原始对象作为值。

        Map<String,Cave> myMap=new HashMap<String,Cave>();
      

      【讨论】:

        【解决方案7】:

        您可以简单地创建一个方法来通过对象的名称获取对象。

        public Party getPartyByName(String name) {
            for(Party party : parties) {
                if(name.equalsIgnoreCase(party.name)) {
                    return party;
                }
            }
            return null;
        }
        

        【讨论】:

          猜你喜欢
          • 2018-05-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-07-19
          • 2014-10-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多