通过使ArrayList(或其他Collection)成为最终形式,我们可以获得哪些优点/缺点?我仍然可以将新元素添加到ArrayList中,删除元素并进行更新。但是,什么才是最终的效果呢?
Answers:
但是,什么才是最终的效果呢?
这意味着您不能重新绑定变量以指向其他集合实例:
final List<Integer> list = new ArrayList<Integer>();
list = new ArrayList<Integer>(); // Since `list' is final, this won't compile
出于风格考虑,我声明了大多数我不打算更改为的引用final
。
我仍然可以将新元素添加到ArrayList中,删除元素并进行更新。
如果需要,可以使用Collections.unmodifiableList()
以下方法防止插入,移除等:
final List<Integer> list = Collections.unmodifiableList(new ArrayList<Integer>(...));
final
提高清晰度?
使变量 final
可确保您在分配该目标引用后不能重新分配该目标。如您所述,您仍然可以使用列出的方法进行更改。
如果您将final
关键字与Collections.unmodifiableList结合使用,则会产生可能要实现的行为,例如:
final List fixedList = Collections.unmodifiableList(someList);
结果导致fixedList
不能更改由指向的列表。但是请注意,仍然可以通过someList
引用对其进行更改(因此,请确保在此赋值后它不在范围内。)
您不能像aix所说的那样将其重新绑定到其他集合。
示例:结合不可变列表实现,您可以获得可以公开使用的安全成员。
示例:当您依赖于该引用不变时,您需要最终的。例如,在同步方案中就是如此。
可能还有更多的例子。如果您根本不打算更改引用,则将成员声明为final是一种好方法。
要获得一个真正不变的列表,您必须对列表内容进行深层复制。UnmodifiableList只会使引用列表有些不可变。现在,随着大小的增加,对列表或数组进行深拷贝将对内存造成困难。您可以使用序列化/反序列化并将数组/列表的深层副本存储到临时文件中。该设置程序将不可用,因为成员变量需要是不变的。getter会将成员变量序列化为文件,然后对其进行反序列化以获得深层副本。序列化具有进入对象树深处的天生本质。不过,这将确保完全不变,但会降低性能。
package com.home.immutable.serial;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
public final class ImmutableBySerial {
private final int num;
private final String str;
private final ArrayList<TestObjSerial> immutableList;
ImmutableBySerial(int num, String str, ArrayList<TestObjSerial> list){
this.num = num;
this.str = str;
this.immutableList = getDeepCloned(list);
}
public int getNum(){
return num;
}
public String getStr(){
return str;
}
public ArrayList<TestObjSerial> getImmutableList(){
return getDeepCloned(immutableList);
}
private ArrayList<TestObjSerial> getDeepCloned(ArrayList<TestObjSerial> list){
FileOutputStream fos = null;
ObjectOutputStream oos = null;
FileInputStream fis = null;
ObjectInputStream ois = null;
ArrayList<TestObjSerial> clonedObj = null;
try {
fos = new FileOutputStream(new File("temp"));
oos = new ObjectOutputStream(fos);
oos.writeObject(list);
fis = new FileInputStream(new File("temp"));
ois = new ObjectInputStream(fis);
clonedObj = (ArrayList<TestObjSerial>)ois.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
oos.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return clonedObj;
}
}
我想到了这个问题,并从另一个角度对示例进行了编码和添加。
最终的arrayList仍然可以修改,请参考下面的示例并运行它以供参考。
这是带有不可变List声明的不可变类:
public final class ImmutableClassWithArrayList {
final List<String> theFinalListVar = new ArrayList<String>();
}
这是驱动程序:
public class ImmutableClassWithArrayListTester {
public static void main(String[] args) {
ImmutableClassWithArrayList immClass = new ImmutableClassWithArrayList();
immClass.theFinalListVar.add("name");
immClass.theFinalListVar.forEach(str -> System.out.println(str));
}
}
如您所见,主要方法是添加(修改)列表。因此,唯一需要注意的是,不能将对集合类型对象的“引用”重新分配给另一个此类对象。就像上面adarshr的回答一样,您无法执行immClass.theFinalListVar = new ArrayList();。在这里的主要方法。
修改部分确实帮助我理解了这一点,并希望以同样的方式有所帮助。