Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 列表的意外行为<;T>;在爪哇_Java_Android_List - Fatal编程技术网

Java 列表的意外行为<;T>;在爪哇

Java 列表的意外行为<;T>;在爪哇,java,android,list,Java,Android,List,在使用我的应用程序时,我遇到了一个我没有预料到或以前遇到过的行为 考虑这个简单的类: public class A { public long id; public long date; public List<Long> list; /* constructors */ } 公共A类{ 公共长id; 公众长期约会; 公开名单; /*建设者*/ } 现在考虑这2种方法来做同样的事情: /* Approach #1 */ List<A>

在使用我的应用程序时,我遇到了一个我没有预料到或以前遇到过的行为

考虑这个简单的类:

public class A {
    public long id;
    public long date;
    public List<Long> list;

    /* constructors */
}
公共A类{
公共长id;
公众长期约会;
公开名单;
/*建设者*/
}
现在考虑这2种方法来做同样的事情:

/* Approach #1 */

List<A> mList = new ArrayList<A>();
long mLong = ......;
A mA = new A(id, date);

if(!mList.contains(mA))
    mList.add(mA);

mA = mList.get(mList.indexOf(mA));
if(!mA.list.contains(mLong))
    mA.list.add(mLong);



/* Approach #2 */

List<A> mList = new ArrayList<A>();
long mLong = ......;
A mA = new A(id, date);

if(!mA.list.contains(mLong))
    mA.list.add(mLong);

if(!mList.contains(mA))
    mList.add(mA);
/*方法#1*/
List mList=new ArrayList();
龙姆龙=。。。。。。;
A mA=新A(id,日期);
如果(!mList.contains(mA))
列表添加(mA);
mA=mList.get(mList.indexOf(mA));
如果(!mA.list.contains(mLong))
mA.list.add(最小长度);
/*进近#2*/
List mList=new ArrayList();
龙姆龙=。。。。。。;
A mA=新A(id,日期);
如果(!mA.list.contains(mLong))
mA.list.add(最小长度);
如果(!mList.contains(mA))
列表添加(mA);
如您所见,方法2比方法1更有效,也更容易理解。
然而,显然,方法2并没有如预期的那样起作用

代码实际上是在一个循环中运行的,预计在
mList
中可能存在类型为
a
的各种对象,在每个对象的
列表
字段中可能存在数量未知(超过1)的
long

实际情况是,第一种方法工作正常,而第二种方法导致每个对象的
列表中总是有1个
long
值(即使应该有更多)

我个人看不出是什么可能导致它以这种方式工作,这就是为什么我在这里,寻求这个“谜”的答案。我最疯狂的猜测是它与指针有关,或者可能与我不知道的
List
的某些默认行为有关

话虽如此,这种意外行为的原因是什么?


附言:我在发帖前确实尝试过进行搜索,但我真的不知道要搜索什么,所以我没有找到任何有用的东西。

如果有方法
mList.addifassent(mA)
(在将其添加到列表后返回
mA
,或者在
上返回已经存在并匹配
mA
的对象),这会使您的操作变得像

mA = mList.addIfAbsent(mA);
mA.list.addIfAbsent(mLong);
在第二个示例中,当
mA
等价物已经存在时,您显然破坏了这种机制。基本上,您可以将
addIfAbsent(mA)
的定义更改为“如果列表中没有其他对象与之相等,则将
mA
添加到列表中,并返回
mA

您可以提高性能,获得与第二个示例(无bug)相同的结果,如下所示:

int indOfOld = mList.indexOf(ma); 
if (indOfOld != -1)
  ma = mList.get(indOfOld);
else
  mList.add(mA);

if(!mA.list.contains(mLong))
    mA.list.add(mLong);
public boolean equals(Object o) {
    return this == o;
}
这不会降低big-O的复杂性,但至少只需要一个O(n)操作(与工作代码中的两个操作相比)


顺便说一句,这对你和其他人来说可能是显而易见的;如果是这样,请原谅,但是如果这些列表大于数千个元素,如果您使用
HashSet
,或者如果您关心插入顺序,甚至使用
LinkedHashSet
,则可以显著提高性能。在这种情况下,您只需尝试添加一个对象,如果该对象已经存在,则会得到
false
,这只需要花费O(1)个时间。然后,您将
从集合中获取(mA)
,而不是使用
indexOf
的迂回方式,这也是在O(1)时间内。

这是因为
mList.contains(mA)
通过调用
o1.equals(o2)
在内部检查对象的相等性。
equals()
的默认实现如下所示:

int indOfOld = mList.indexOf(ma); 
if (indOfOld != -1)
  ma = mList.get(indOfOld);
else
  mList.add(mA);

if(!mA.list.contains(mLong))
    mA.list.add(mLong);
public boolean equals(Object o) {
    return this == o;
}
显然,这些实例并不相同,因此每次都要添加一个新实例。在类
A
中重写
equals()
,以修复该问题。如果实例具有相同的id,我猜它们是相同的

public boolean equals(Object o) {
    return this.mId == o.mId;
}

第二种方法会导致在每个对象的列表中始终有一个长值(即使应该有更多值)。

问题

A mA=新的A(id,日期);
如果(!mA.list.contains(mLong))

正如您所看到的,您没有从mList获取类A的引用,您正在检查刚刚创建的列表中是否包含long值,该列表只会添加一个。因此,基本上您所做的是创建一个新的类a,在long列表中有1个long值,并添加到mList


另一方面,您的第一种方法是获取已经添加的类A的实例,并检查该长类是否包含在列表中,如果没有,则将其添加到长类列表中。

提供更多代码来复制该问题。另外,使用
Set
而不是
List
来真正提高性能。
mA=mList.get(mList.indexOf(mA))
有什么好处?这是一个无效操作,因为您已经有
mA
!?哦,我现在明白了!我觉得自己很傻,因为我没有早点意识到这一点!非常感谢。