此代码跟踪玩家购买的导弹,并将最新的3枚导弹设置在导弹选项列表的顶部,以便玩家轻松再次购买。玩家购买导弹后,游戏会崩溃,但前提是他们购买了某些导弹或购买了一定数量的导弹。
Process: com.apps.fast.counterforcetest, PID: 16063
java.lang.IndexOutOfBoundsException: Index: 5, Size: 3
at java.util.LinkedList.checkElementIndex(LinkedList.java:555)
at java.util.LinkedList.remove(LinkedList.java:525)
at com.apps.fast.launch.components.ClientDefs.SetMissilePreferred(ClientDefs.java:199)
at com.apps.fast.launch.launchviews.PurchaseLaunchableView$1$1.onClick(PurchaseLaunchableView.java:198)
以下是CLientDefs.java:199中错误指向的代码
public static void SetMissilePreferred(int lMissile) {
// Set a purchased missile to go to the top of the preferred list.
if (MissilePreferences == null)
MissilePreferences = new LinkedList<>();
if (MissilePreferences.contains(lMissile))
MissilePreferences.remove(lMissile); //<---- Line 199
MissilePreferences.push(lMissile);
if (MissilePreferences.size() > PREFERENCE_LIST_SIZE)
MissilePreferences.removeLast();
}
MissilePreferences
是一个整数列表。
这里有点混乱:
if (MissilePreferences.contains(lMissile))
MissilePreferences.remove(lMissile);
lMissile
是int
,对吧?代表身份证?因此,当您调用contains
时,您正在检查该ID是否存在于MissilePreferences
中。您想知道List
是否包含该int
。
这是contains
:的方法签名
public boolean contains(Object o)
它不像int
那样需要基元,它需要Object
——所以int
被自动装箱到Integer
中——这是有道理的,因为List
也不能包含基元,只能包含对象。MissilePreferences
是Integer
s的列表。
所以没关系,它将您的int
转换为Integer
,并告诉您它是否存在于Integer
s的列表中,完美!但是你用原来的int
调用remove
。这种方法有两个版本需要一个参数:
public boolean remove(Object o)
从该列表中删除指定元素的第一个出现(如果存在(。
public E remove(int index)
删除此列表中指定位置的元素。
它们做了两件截然不同的事情。Object
版本从列表中删除该对象的第一个实例。int
版本将int
视为索引,并删除该位置中的任何内容。
当您使用contains
时,您将int
视为要查找的列表中的一个元素,它会自动转换为Integer
。你想对remove
做同样的事情,但有一个不同版本的方法,它采用了你直接提供的int
。显然,它不会自动装箱并调用其他方法!你必须自己做:
Integer missileId = new Integer(lMissile);
// explicitly passing an Integer object to both - only crucial for #remove
if (MissilePreferences.contains(missileId))
MissilePreferences.remove(missileId);
这就是你必须注意的——除了数组和你可能在其他地方遇到的一些特殊类之外,集合对象不包含基元,所以你经常想显式地使用它们包含的Object
包装版本。在这种情况下,对int
特别重要!
也就是说,你可以这样做:
MissilePreferences.remove(new Integer(lMissile));
不需要使用contains
——只需调用remove
,它就会删除第一个匹配对象(如果它有(。如果它删除了任何内容,它将返回true,以防您需要检查
尝试调试代码,以便了解列表中的元素以及要删除的元素。当你只是根据列表中的元素的值访问它时,我仍然困惑于如何获得索引越界异常。