简体   繁体   English

ArrayList.remove(Object o)不遍历内容

[英]ArrayList.remove(Object o) not iterating over contents

So, I've been sitting on this problem for several hours now and I'm out of ideas. 因此,我已经在这个问题上坐了好几个小时了,但我没有主意。 I looked through the documentation (ArrayList and Object) and read a lot of Stackoverflow questions regarding ArrayList.remove(Object obj) , but nothing helped. 我浏览了文档(ArrayList和Object),并阅读了许多有关ArrayList.remove(Object obj)的Stackoverflow问题,但没有任何帮助。

I try to implement a simulation (game?) where I have a Cell[][] to store the map. 我尝试实现一个模拟(游戏?),在那里我有一个Cell [] []存储地图。 Each Cell has inhabitants (class Person) stored in an ArrayList, which move one step every iteration. 每个单元都有一个存储在ArrayList中的居民(Person类),该居民每次迭代都移动一个步骤。 When a Person moves I add them to the next Cell and remove them from the old one. 当一个人移动时,我将它们添加到下一个单元中,并将其从旧单元中删除。 Or rather try, as the remove part doesn't work yet. 还是尝试一下,因为删除部分尚不可用。

My Question: I need help implementing the ArrayList.remove(Object obj) method. 我的问题:我需要帮助来实现ArrayList.remove(Object obj)方法。
What I got so far: 我到目前为止所得到的:

class Cell
{
    private final int x;
    private final int y;
    ArrayList<Person> inhabs = new ArrayList<Person>();

    /** this method is called by a Person that wants to move to another Cell **/
    public void moveMe(Person p){
        try{
            Cell northOfHere = grid.grid[y-1][x]//direction will be changed to be random
            northOfHere.add(p);
        }catch(ArrayIndexOutOfBoundsException ex){/*person falls from the edge of the world*/}

        inhabs.remove(p); //this is not working right
    }

    public void add(Person p){
        inhabs.add(p);
    }
}

Class Person: 班级人员:

class Person extends Object
{
    private int health;
    private int strength;
    private int food;
    private final int nation;

    @Override
    public boolean equals(Object obj){
        if(obj == null){return false;}
        if(obj == this){return true;}
        if(!(obj instanceof Person)){return false;}

        Person p = (Person)obj;
        return p.toString().equals(toString());
    }

    @Override
    public int hashCode(){
        return toString().hashCode();
    }

    @Override
    public String toString(){
        return String.format("Health: %03d, Strength: %03d, Food: %03d, Nation: %02d", health, strength, food, nation);
    }
}

Some key points: 一些关键点:

  • The inhabs.remove(p); inhabs.remove(p); is not working right how I want it. 我多么希望这是不工作 的权利
  • It does work in the first iteration, but in the second it only returns false . 它在第一次迭代中确实起作用,但是在第二次迭代中,它仅返回false
  • The first iteration over the Person.equals(Object obj) by the ArrayList always returns true because of the line if(obj == this){return true;} . ArrayList对Person.equals(Object obj)的第一次迭代始终返回true,这是因为if(obj == this){return true;}
  • On the second iteration it never even starts to compare the objects (?!?). 在第二次迭代中,它甚至从未开始比较对象(?!?)。
  • The ArrayList is not empty. ArrayList不为空。

I understand that this is a very specific question, however I could not find anything that adressed the problem of the ArrayList not even going over the Elements in it. 我知道这是一个非常具体的问题,但是我找不到任何解决ArrayList问题的东西,甚至没有遍历其中的Elements。

edit: more Code. 编辑:更多代码。 Probably irrelevant to the problem, but i'll post it anyway, for context. 可能与该问题无关,但出于上下文,我还是将其发布。

class Grid{        
    Cell[][] grid;

    public Grid(Cell[][] in){
        grid = in; //has some cells with people in it.
    }

    //simply iterates over all cells
    public void tick(){
        for(int y = 0; y<grid.length; y++){
            for(int x = 0; x<grid[y].length; x++){
                grid[y][x].tick();
            }
        }
}


class Cell
{
    Grid grid;

    public Cell(/*some constants constants*/ Grid g, ArrayList<Person> inh){
        grid = g;
        if(inh == null){
            inhabs = new ArrayList<Person>();
        }else{
            inhabs = inh;
        }
    }

    //tells every person to make a step
    public void tick(){
        for(Person p : inhabs.toArray(new Person[inhabs.size()])){
            p.tick();
        }
    }

    //and all the other methods from above, of course
}


class Person extends Object
{
    Cell cell;

    public Person(Cell c, int h, int s, int f, int n){
        cell = c;
        health = h;
        strength = s;
        food = f;
        nation = n;
    }

    public void tick(){
        //for testing, later more options
        cell.moveMe(this);
    }

    //and all the other methods from above, of course
}

This can't be reproduced, here is a small test with your logic : 无法复制,这是您的逻辑测试:

public static void main(String args[]) {
    Person p1 = new Person(10, 2, 2, 1);
    Person p2 = new Person(10, 2, 2, 2);
    Person p3 = new Person(10, 2, 2, 3);

    List<Person> list = new ArrayList<Person>();
    list.add(p1);
    list.add(p2);
    list.add(p3);

    System.out.println(list.remove(p2)); //true
    System.out.println(list.remove(p2)); //false
    System.out.println(list.remove( new Person(10, 2, 2, 3))); //true
}

My guess is that you don't use the correct Person , you either construct a new instance without giving every variables correctly. 我的猜测是您没有使用正确的Person ,而是在没有正确给出每个变量的情况下构造了一个新实例。 (Note that you didn't provide the constructor here, with a final value, this can't work...) (请注意,您未在此处为构造函数提供final值,因此无法使用...)


I have read your code. 我已经阅读了您的代码。 Your problem is simple. 您的问题很简单。

You tick a Cell that will tick every Person in that Cell . tick一个Cell ,该CelltickCell每个Person From there you move that Person from the current Cell using Cell.moveMe(Person p); 从那里,您可以使用Cell.moveMe(Person p);从当前Cell移动该Person Cell.moveMe(Person p); . You do move the instance in the new Cell.inhabs and remove it from the current one. 您确实将实例移动到新的Cell.inhabs ,并将其从当前实例中删除。 BUT since you have references of all your instance in both way, your Person is never instructed to which Cell it is moved ... so when you call : 但是由于您都以两种方式都引用了您的所有实例,因此永远不会指示您的“ Person将其移动到哪个Cell ...因此,当您调用时:

public void tick(){
    //for testing
    cell.moveMe(this);
}

cell is still the initial position... but that cell don't hold that person, so it can't remove the instance received. cell仍然是初始位置...但是该cell无法容纳该人,因此它无法删除收到的实例。

A simple correction would be to return the cell where you move him into : 一个简单的更正是将您将其移至其中的单元格返回:

public Cell moveMe(Person p){
    Cell northOfHere = null;
    try{
        northOfHere = grid.grid[y-1][x];
        northOfHere.add(p);
    }catch(ArrayIndexOutOfBoundsException ex){
        System.out.println("fell from edge");/*person falls from the edge of the world*/
    }
    System.out.format("Remove from %s person %s%n", this, p);
    System.out.println("removed: " + inhabs.remove(p));
    return northOfHere;
}

And update that cell : 并更新该单元格:

public void tick(){
    //for testing
    cell = cell.moveMe(this);
}

I agreed here to keep cell to null when he "feel off the map", as it remain outside of any cell. 我同意在他“离开地图”时将cell保持为null ,因为它保留在任何单元格之外。

As Andy Turner pointed out, you need to fix the equals() method. 正如Andy Turner指出的那样,您需要修复equals()方法。 In Person class the equals() must be precise. Person类中, equals()必须精确。

There is a contract between hashCode() and equals() : if one object equals another, then their hashCode() must be the same. hashCode()equals()之间有一个约定 :如果一个对象等于另一个,则它们的hashCode()必须相同。 So the easiest way is to piggyback equals() too on toString() : 因此,最简单的方法就是在toString()上也搭载equals() toString()

class Person // automatically extends Object
{

    // ...
    @Override

    public boolean equals(Object obj) {
        return (obj instanceof Person) && // instanceof is null-safe
            this.toString().equals((Person) obj).toString();
    }
}

Honestly, I don't like writing equals() and hashCode() methods, unless absolutely necessary. 老实说,除非绝对必要,否则我不喜欢编写 equals()hashCode()方法。 They are cumbersome and error-prone. 它们麻烦且容易出错。 In this case, it doesn't look absolutely necessary. 在这种情况下,它看起来并不是绝对必要的。 There are a few alternatives: 有几种选择:

  • generate them with your IDE 用您的IDE生成它们
  • use apache EqualsBuilder and HashCodeBuilder . 使用apache EqualsBuilderHashCodeBuilder Here is a nice example. 是一个很好的例子。

With HashCodeBuilder you'd write code like this: 使用HashCodeBuilder您可以编写如下代码:

@Override
public int hashCode() {
   return new HashCodeBuilder()
      .append(this.health)
      .append(this.strength)
      ...
      .toHashCode();
}

With EqualsBuilder you'd write code like this: 使用EqualsBuilder您可以编写如下代码:

@Override
public boolean equals(Object obj) {
      if (obj instanceof Person == false)
      {
        return false;
      }
      if (this == obj)
      {
         return true;
      }

      Person that = (Person) obj;
      return new EqualsBuilder()
        .append(this.health, that.health)
        .append(this.strength, that.strength)
        ...
        .isEquals();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM