12 ответов:
но какой эффект делает это финал?
это означает, что вы не можете повторно привязать переменную, чтобы указать на другой экземпляр коллекции:
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 List<String> list = new ArrayList<String>(); list = new LinkedList<String>(); ^ Compiler error hereЕсли вы действительно хотите неизменяемый список, вы должны использовать
Collections.unmodifiableList()метод.
создание переменной
finalубедитесь, что вы не можете повторно назначить эту ссылку objest после ее назначения. Как вы упомянули, Вы все еще можете использовать этот список методов для внесения изменений.если вы объедините
finalключевое слово с использованием коллекций.unmodifiableList, вы ge поведение, которое вы, вероятно, пытаетесь достичь, например:final List fixedList = Collections.unmodifiableList(someList);это приводит к тому, что список, на который указывает
fixedListизменить нельзя. Остерегайтесь, однако, что он может все еще быть изменения черезsomeListссылка (поэтому убедитесь, что он находится вне области действия после этого asignment.)
finalимеет много последствий при многопоточности.
- JMM четко определяет a
finalзавершение инициализации поля гарантировано.что не ясно определено:
- компиляторы могут свободно переупорядочивать их через барьеры памяти.
- компиляторы всегда могут прочитать кэшированную копию.
Это не влияет на то, что вы можете сделать с ArrayList, как вы справедливо наблюдаете - сам ArrayList все еще изменчив. Вы только что сделали ссылку неизменной.
но создание переменной final имеет и другие преимущества:
- это предотвращает изменение переменной, если она должна оставаться постоянной. Это может помочь предотвратить будущие ошибки.
- делая переменных
finalможет помочь компилятору сделать определенную производительность оптимизации.В общем, чем больше вещей вы сделаете неизменными, тем лучше. Поэтому создание окончательных ссылок (даже если они являются ссылками на изменяемые объекты), как правило, является хорошей идеей.
Final является ключевым словом или зарезервированным словом в java и может применяться к переменные-члены, методы, класс и локальные переменные в Java. Когда-то ты сделать ссылку окончательной вы не можете изменить эту ссылку и компилятор проверит это и вызовет ошибку компиляции, если вы попытаетесь для повторной инициализации конечных переменных в java.
вы не можете повторно привязать его к другой коллекции, как сказал aix.
пример: В сочетании с реализацией неизменяемого списка вы получаете безопасные члены, которые вы можете сделать общедоступными.
пример: Когда вы полагаетесь на эту ссылку, она не меняется, вам нужен финал. Это верно, например, в сценариях синхронизации.
там может быть гораздо больше примеров. Это хороший стиль для объявления членов final, если вы не собираетесь изменять ссылку на все.
чтобы получить действительно неизменяемый список, вам придется сделать глубокие копии содержимого списка. UnmodifiableList только сделает список ссылок несколько неизменным. Теперь создание глубокой копии списка или массива будет сложно для памяти с растущим размером. Вы можете использовать сериализацию / десериализацию и хранить глубокую копию массива/списка во временном файле. Сеттер не будет доступен, поскольку член varaible должен быть неизменяемым. Геттер будет сериализовать член переменная в файл, а затем десиализировать его, чтобы получить глубокую копию. Сериализация имеет врожденную природу погружения в глубины дерева объектов. Это обеспечило бы полную неизменность при некоторой стоимости производительности.
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; } }
Я лично отмечаю поле коллекций моих классов как
finalчтобы сохранить пользователей моего класса от проверки, является ли он нулевым или нет. Это работает, потому что, как только значение уже назначено конечной переменной, оно никогда не может быть переназначено другому значению, включая null.
по существу, то, что вы пытаетесь достичь здесь, делает список неизменным, я думаю. Однако, когда вы отмечаете ссылку на список final, это означает, что ссылка не может быть указана на любой другой объект списка, кроме этого.
Если вы хотите, чтобы окончательный (неизменяемый) ArrayList пошел для коллекций классов утилиты метод коллекции.unmodifaibleList (список ) вместо этого.
Я пришел к мысли об этом же вопросе и закодировал и пример, чтобы добавить к объяснению еще один угол.
окончательный arrayList все еще может быть изменен, обратитесь к приведенному ниже примеру и запустите его, чтобы увидеть для себя.
вот неизменяемый класс с неизменяемым объявлением списка:
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 (); в основном методе здесь.
часть модификации действительно помогла мне понять это и надеюсь, что это поможет таким же образом.
Comments