我有类SpeexRunner,如下所示,构造函数接受两个参数:布尔变量和LinkedList<short[]>
。如下: -
public class SpeexRunner implements Runnable {
public boolean stopThread;
LinkedList<short[]> dataList;
public SpeexRunner(boolean val_stopThread, LinkedList<short[]> dataRef){
this.stopThread = val_stopThread;
dataList = dataRef;
}
@Override
public void run() {
//add objects in dataList;
// change / remove dataList Objects
}
}
我的问题是: - 如果我在run()中更改dataList,更改是否会反映到原来的列表中,而这个列表是在其他地方声明的?
答案 0 :(得分:5)
如果我在run()中更改dataList,更改是否会反映到在其他地方声明的原始列表?
是。您的构造函数会在列表中收到引用,而不是它的副本。如果您要复制它,则必须使用LinkedList
copy constructor。然后,您将拥有列表的自己的副本。但请注意,两个列表上的条目仍然是共享的,因为条目是数组(short[]
),并且数组是通过引用存储的。
这可能是最好的例子:
import java.util.*;
public class ListExample {
public static final void main(String[] args) {
List<short[]> list;
// Direct use (no copies)
list = new LinkedList<short[]>();
list.add(new short[] { 0, 0, 0 });
System.out.println("list.size() before direct use: " + list.size());
System.out.println("list.get(0)[0] before direct use: " + list.get(0)[0]);
new DirectUser(list).doSomething();
System.out.println("list.size() after direct use: " + list.size());
System.out.println("list.get(0)[0] after direct use: " + list.get(0)[0]);
// Output, note how both the list and its contents have been changed:
// list.size() before direct use: 1
// list.get(0)[0] before direct use: 0
// list.size() after direct use: 2
// list.get(0)[0] after direct use: 1
// Copying the list, but note that the entries are shared by both lists:
list = new LinkedList<short[]>();
list.add(new short[] { 0, 0, 0 });
System.out.println("list.size() before copy-list use: " + list.size());
System.out.println("list.get(0)[0] before copy-list use: " + list.get(0)[0]);
new CopyListUser(list).doSomething();
System.out.println("list.size() after copy-list use: " + list.size());
System.out.println("list.get(0)[0] after copy-list use: " + list.get(0)[0]);
// Output, note how our list didn't change (it doesn't have a new entry), but
// the entry at index 0 *was* changed:
// list.size() before copy-list use: 1
// list.get(0)[0] before copy-list use: 0
// list.size() after copy-list use: 1
// list.get(0)[0] after copy-list use: 1
// "Deep" copying, both the list and its entries:
list = new LinkedList<short[]>();
list.add(new short[] { 0, 0, 0 });
System.out.println("list.size() before deep-copy use: " + list.size());
System.out.println("list.get(0)[0] before deep-copy use: " + list.get(0)[0]);
new DeepCopyUser(list).doSomething();
System.out.println("list.size() after deep-copy use: " + list.size());
System.out.println("list.get(0)[0] after deep-copy use: " + list.get(0)[0]);
// Output, note that neither the list nor its entries was affected by the call:
// list.size() before deep-copy use: 1
// list.get(0)[0] before deep-copy use: 0
// list.size() after deep-copy use: 1
// list.get(0)[0] after deep-copy use: 0
System.exit(0);
}
static class DirectUser {
List<short[]> items;
DirectUser(List<short[]> items) {
// DirectUser doesn't copy the list
this.items = items;
}
void doSomething() {
this.items.get(0)[0] = 1;
this.items.add(new short[] { 2, 2, 2 });
}
}
static class CopyListUser {
List<short[]> items;
CopyListUser(List<short[]> items) {
// CopyListUser copies the list, but both lists still share items
this.items = new LinkedList<short[]>(items);
}
void doSomething() {
this.items.get(0)[0] = 1;
this.items.add(new short[] { 2, 2, 2 });
}
}
static class DeepCopyUser {
List<short[]> items;
DeepCopyUser(List<short[]> items) {
// DeepCopyUser copies the list AND each entry
this.items = new LinkedList<short[]>();
for (short[] entry : items) {
this.items.add(Arrays.copyOf(entry, entry.length));
}
}
void doSomething() {
this.items.get(0)[0] = 1;
this.items.add(new short[] { 2, 2, 2 });
}
}
}
当DirectUser
使用列表时,在我们的调用代码中,我们看到了对列表的更改(因为它变得更长)及其内容(第一个条目的第一个插槽从0
更改为{ {1}})。
当1
使用它时,它创建了列表的副本,因此我们在调用代码中没有看到对列表的任何更改(它没有变得更长) 。但我们确实看到第一个条目的更改(因为两个列表共享相同的数组对象) - 第一个插槽再次从CopyListUser
更改为0
。
当1
使用它时,它会将列表和的副本作为每个条目的副本,因此事情完全完全断开。我们的调用代码没有看到对列表或其项目的更改。
答案 1 :(得分:3)
如果我在run()中更改dataList,更改是否会反映到在其他地方声明的原始列表?
简短回答:是的。
答案稍长:是的,因为参数总是通过Java引用传递。
(您可能使用LinkedList
的(假设的)子类禁止或忽略更改。在这种情况下,尝试的更改将导致异常或无效。但是,这样做不正当......)
答案 2 :(得分:2)
是的,因为线程会引用列表,而不是列表的副本。请注意,LinkedList
未同步:
如果多个线程同时访问链表,并且至少有一个线程在结构上修改了列表,则必须在外部进行同步。
答案 3 :(得分:2)
如果您在列表中添加/删除元素,则可以从其余代码中看到更改。请注意,如果您使用多个线程,则需要使用同步来保证更改可见。
另一方面,如果您不希望更改转义您的类,您可以在构造函数中创建一个新列表并添加原始列表中的所有项目。在这种情况下,从外部看不到对列表的更改,但如果您对列表中的项目进行更改,则会对这些更改进行更改。