java - 如何循环在循环期间发生变化的 ArrayList

标签 java arraylist

我有一个 Sprite 类:

public class Sprite {
    public static ArrayList<Sprite> sprites = null;
    private Texture texture = null;

    public Sprite(Texture texture) {
        sprites.add(this);
        this.texture = texture;
    }

    public void render(SpriteBatch batch) {
        batch.draw(texture);
    }

    public void dispose() {
        sprites.remove(this);
    }
}

在我创建任何 Sprite 之前,我确保 Sprite 类具有对将要渲染的 Sprite 池的引用:

public class Main extends ApplicationAdapter {
    private static ArrayList<Sprite> sprites = new ArrayList<Sprite>();

    public Main() {
        Sprite.sprites = sprites;

        new Sprite("texture.png");
    }

    @Override
    public void render(SpriteBatch batch) {
        for (int i = 0; i < sprites.size(); i++)
            sprites.get(i).render(batch);
    }
}

所以现在当我创建一个新的 sprite 时,它​​会自动呈现,而无需我手动将它添加到 ArrayList 中。

问题是 sprite 可以在 for 循环运行期间被释放,因此某些 sprite 不会在该特定帧渲染。

我不想向后循环遍历项目,例如:

for (int i = sprites.size() - 1; i >= 0; i--)
    sprites.get(i).render(batch);

因为这会使我的 sprite 乱序(应该在顶部的 sprite 将被覆盖)。

到目前为止,我唯一的解决方案是使用另一个 ArrayList 来跟踪要处理的对象,例如:

public class Sprite {
    public static ArrayList<Sprite> sprites = null, garbage = null;

    //everything else the same

    public void dispose() {
        garbage.add(this);
    }
}

然后在渲染过程中,我首先从 Sprite 中移除所有垃圾,然后渲染 Sprite :

for (int i = 0; i < garbage.size(); i++)
    sprites.remove(garbage.get(i));
garbage.clear();

for (int i = 0; i < sprites.size(); i++)
            sprites.get(i).render(batch);

这个方法可行,但我感觉效率不高。 (有两个数组列表?然后做两个 for 循环?)

有什么方法可以循环遍历 Sprites 而不会在处置 Sprite 时跳过 Sprite?我不想向后循环 Sprites,因为它会打乱顺序。

我现在已经使用同步列表对此进行了测试,但我无法使其正常工作。

Testable code , (与 java.util.ConcurrentModificationException)

import java.util.*;

class Ideone {

    public static class Sprite {
        public static List<Sprite> sprites = null;
        public int age = 0;

        public Sprite() {
            synchronized(sprites) {
                sprites.add(this);
            }
        }

        public void render() {
            age++;
            if (age > 30)
                dispose();
        }

        public void dispose() {
            synchronized(sprites) {
                sprites.remove(this);
            }
        }
    }

    private static List<Sprite> sprites = Collections.synchronizedList(new ArrayList<Sprite>());

    public static void main(String[] args) {
        Sprite.sprites = sprites;

        new Sprite();
        new Sprite();

        for (int i = 0; i < 60; i++)
            render();

    }

    public static void render() {
        synchronized(sprites) {
            Iterator<Sprite> iterator = sprites.iterator();
            while (iterator.hasNext())
                iterator.next().render();
        }
    }
}

最佳答案

首先,如果从多个线程访问sprites 列表,您需要同步访问它或使用线程安全数据结构(例如 CopyOnWriteArrayList 或 CopyOnWriteArraySet)。

在这种情况下,

Sprite.dispose 可以直接从 sprites 中移除自己。

关于java - 如何循环在循环期间发生变化的 ArrayList,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30488297/

相关文章:

java - getParcelableArrayList 返回空列表

java - java中main中声明的变量本质上是静态的吗?

java - java 反转alpha值

java - 如何筛选其中包含 WebElement 的列表

java - 如何在数组列表中查找数组列表的索引?

对象 myList 的 Java 新 ArrayList

java - Big Word 应用程序,使用 Canvas Javafx,有趣的挑战

java - 在 JavaEE Maven 项目中使用 Hibernate 时出现 "java.lang.NoClassDefFoundError: javax/persistence/criteria/Selection"错误

java - OnItemClickListener 消费 onClickListener 事件

java - 包cucumber.api.java.en 不存在cucumber