最终的ArrayList是什么意思?

时间:2012-05-25 08:08:22

标签: java arraylist final

通过使ArrayList(或其他Collection)最终获得哪些优点/缺点?我仍然可以添加ArrayList新元素,删除元素并更新它。但是什么影响使它成为最终的?

12 个答案:

答案 0 :(得分:120)

  

但是它的最终效果是什么呢?

这意味着您无法重新绑定变量以指向其他集合实例

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>(...));

答案 1 :(得分:14)

这只是意味着您无法重新分配其参考。尝试执行以下操作会导致编译器错误。

final List<String> list = new ArrayList<String>();

list = new LinkedList<String>();
     ^
     Compiler error here

如果你真的想要一个不可变列表,你应该使用Collections.unmodifiableList()方法。

答案 2 :(得分:8)

例如,您将无法使用new ArrayList修改其引用。

答案 3 :(得分:5)

创建变量final可确保在分配后不能重新分配该对象引用。如您所述,您仍然可以使用该列表方法进行更改。

如果您将final关键字与Collections.unmodifiableList的使用结合起来,那么就可以了解您可能尝试实现的行为,例如:

final List fixedList = Collections.unmodifiableList(someList);

这导致fixedList指向的列表无法更改。但要注意它仍然可以通过someList引用进行更改(因此请确保在此对齐后它超出范围。)

答案 4 :(得分:5)

final在多线程下会产生很多后果。

  1. JMM明确定义final字段的初始化完成得到保证。
  2. 没有明确定义的是:

    1. 编译器可以跨内存屏障对它们进行重新排序。
    2. 编译器始终可以读取缓存副本。

答案 5 :(得分:3)

正如您正确观察到的那样,它不会影响您对ArrayList所能做的事情 - ArrayList本身仍然是可变的。您刚刚将引用设为不可变。

但是制作变量最终确实还有其他好处:

  • 如果预期变量保持不变,它会阻止变量被更改。这可以帮助防止未来的错误。
  • 使变量final可以帮助编译器进行某些性能优化。

一般来说,你制作不变的东西越多越好。因此,使引用最终(即使它们是对可变对象的引用)通常是一个好主意。

答案 6 :(得分:1)

  

Final是java中的关键字或保留字,可以应用于   Java中的成员变量,方法,类和局部变量。一旦您   作出参考最后你不能改变那个参考   如果你尝试,编译器将验证这一点并引发编译错误   重新初始化java中的最终变量。

答案 7 :(得分:1)

你不能像aix所说的那样将它重新绑定到不同的集合中。

实施例: 与不可变列表实现相结合,您将获得可以公开使用的安全成员。

实施例: 当你依赖那个参考不改变你需要最终。例如,在同步方案中也是如此。

可能还有更多例子。如果您根本不打算更改引用,那么声明成员final是一种很好的方式。

答案 8 :(得分:1)

我个人将我的类的collections字段标记为final,以保存我的类的用户不检查它是否为null。这是有效的,因为一旦将值分配给最终变量,就永远不会将其重新分配给另一个值,包括null。

答案 9 :(得分:1)

要获得真正不可变的列表,您必须制作列表内容的深层副本。 UnmodifiableList只会使引用列表有些不可变。 现在制作List或数组的深层副本对于内存越来越大而言将是艰难的。 您可以使用序列化/反序列化并将数组/列表的深层副本存储到临时文件中。由于成员变量需要不可变,因此setter将不可用。 getter会将成员变量序列化为一个文件,然后对其进行desialize以获得一个深层副本。 Seraialization具有进入对象树深处的天生特性。这样可以确保在某些性能成本下完全不变。

 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;
    }
}

答案 10 :(得分:0)

基本上你在这里想要实现的是让我觉得列表不可变。但是,当您标记列表引用final时,它意味着引用不能指向除此之外的任何其他列表对象。

如果你想要一个final(不可变)ArrayList,那就去找Collections类的实用工具方法Collections.unmodifaibleList(list)。

答案 11 :(得分:0)

我开始考虑同样的问题,编码和例子从另一个角度添加到解释中。

  

最终的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));
 }
}
  

如您所见,主要方法是添加(修改)列表。因此,唯一需要注意的是&#34;参考&#34;对于集合类型的对象,不能重新分配给另一个这样的对象。正如上面的adarshr的回答,你不能做immClass.theFinalListVar = new ArrayList();在这里的主要方法。

修改部分确实帮助我理解了这一点,并希望它有同样的帮助。