2012-05-25 13 views
50

Jakie wady/zalety możemy uzyskać, dokonując ostatecznego wyboru ArrayList (lub innej Kolekcji)? Nadal mogę dodawać do ArrayList nowe elementy, usuwać elementy i aktualizować je. Ale jaki jest efekt, dzięki czemu jest on ostateczny?jaki jest sens ostatecznej listy ArrayList?

+1

gdy tablica jest zadeklarowana jako ostateczna, stan obiektu przechowywanego w tablicy można zmodyfikować. Musisz zrobić to niezmiennym, aby nie pozwolić na modyfikacje. –

Odpowiedz

103

Ale jaki jest efekt końcowy?

To oznacza, że ​​nie można ponownie powiązać zmienną, aby wskazywała na inny przykład zbiórki:

final List<Integer> list = new ArrayList<Integer>(); 
list = new ArrayList<Integer>(); // Since `list' is final, this won't compile 

W gruncie stylu Oświadczam najwięcej odniesień, że nie zamierza zmieniać jak final.

Nadal mogę dodawać do ArrayList nowe elementy, usuwać elementy i aktualizować je.

Jeśli chcesz, możesz uniemożliwić wstawianie, usuwanie etc za pomocą Collections.unmodifiableList():

final List<Integer> list = Collections.unmodifiableList(new ArrayList<Integer>(...)); 
+3

+1 Korzystanie z pól końcowych może poprawić przejrzystość, ponieważ zajęcia mogą być dość długie. Nie używam ostatecznego w metodach tak bardzo, jak staram się przełamywać długie metody. –

13

To po prostu oznacza, że ​​nie można ponownie przypisać jej odwołanie. Próba wykonania czynności podobnej do poniższej spowoduje błąd kompilatora.

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

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

Jeśli naprawdę chcesz listę niezmienny, należy użyć metody Collections.unmodifiableList().

7

Nie można na przykład zmienić jego odwołania, korzystając z numeru new ArrayList.

1

Finał jest słowem kluczowym lub słowem zastrzeżonym w języku Java i można go stosować do zmiennych członkowskich, metod, zmiennych klas i lokalnych w języku Java. Po wykonaniu ostatecznej wersji referencyjnej nie można zmienić tego odwołania. Kompilator sprawdzi to i zgłosi błąd kompilacji, jeśli spróbujesz ponownie zainicjować zmienne końcowe w Javie.

3

Nie ma wpływu na to, co można zrobić z ArrayList, jak słusznie obserwujesz - sama tablica ArrayList jest wciąż zmienna. Właśnie dokonałeś odniesienia niezmiennego.

Ale dokonywania Ostatnia zmienna posiada inne zalety:

  • zapobiega zmienną przed zmianą, jeśli oczekuje się, aby zatrzymać się na stałym poziomie. Pomoże to zapobiec przyszłym błędom.
  • Tworzenie zmiennych final może pomóc kompilatorowi w dokonaniu pewnych optymalizacji wydajności.

Ogólnie rzecz biorąc, im więcej rzeczy robisz niezmiennie, tym lepiej. Zatem tworzenie ostatecznych odniesień (nawet jeśli są to odniesienia do zmiennych obiektów) jest ogólnie dobrym pomysłem.

1

Nie można ponownie powiązać go z inną kolekcją, jak powiedział aix.

Przykład: W związku z wdrażaniem niezmiennych list otrzymujesz bezpiecznych członków, które możesz upublicznić.

Przykład: Gdy polegasz na tym, że referencja się nie zmienia, potrzebujesz ostatecznego. Dotyczy to na przykład scenariuszy synchronizacji.

Może być o wiele więcej przykładów. Dobrze jest ogłaszać członków końcowych, jeśli nie zamierzacie w ogóle zmieniać odniesienia.

5

Wprowadzanie zmiennej final powoduje, że nie można ponownie przypisać tego odniesienia do odniesienia po jego przypisaniu. Jak już wspomniałeś, wciąż możesz użyć tej listy, by wprowadzić zmiany.

Jeśli połączyć słowa kluczowego final z wykorzystaniem Collections.unmodifiableList, ty ge zachowanie jesteś prawdopodobnie staramy się osiągnąć, na przykład:

final List fixedList = Collections.unmodifiableList(someList); 

ma to jako skutek, że lista wskazywanego przez fixedList może nie być zmienione. Uważaj jednak, że nadal można to zmienić za pomocą odnośnika someList (więc upewnij się, że jest poza zakresem po tym przypisaniu).

1

Ja osobiście zaznaczam pole kolekcji moich zajęć jako final, aby oszczędzić użytkownikom mojej klasy przed sprawdzeniem czy jest zerowy czy nie. Działa to, ponieważ gdy wartość jest już przypisana do zmiennej końcowej, nigdy nie można jej przypisać do innej wartości, w tym wartości null.

3

final ma wiele konsekwencji w przypadku wielowątkowości.

  1. JMM wyraźnie określa, że ​​zagwarantowane jest zakończenie inicjalizacji pola final.

Co nie jest jasno określona jest:

  1. Kompilatory są wolne, aby zmienić kolejność ich przez bariera pamięci.
  2. Kompilatory zawsze mogą odczytać kopię z pamięci podręcznej.
1

Aby uzyskać naprawdę niezmienną listę, będziesz musiał wykonać głęboką kopię zawartości listy. UnmodifiableList uczyniłaby listę referencji jedynie niezmienną. Teraz tworzenie głębokiej kopii listy lub tablicy będzie trudne w pamięci wraz z rosnącym rozmiarem. Można użyć serializacji/deserializacji i zapisać głęboką kopię tablicy/listy w pliku tymczasowym. Seter nie będzie dostępny, ponieważ zmienna członka musi być niezmienna. Program pobierający szereguje zmienną składową w pliku, a następnie desyalizuje ją, aby uzyskać głęboką kopię. Seraializacja ma wrodzoną naturę wchodzenia w głębiny drzewa obiektów. Zapewniłoby to całkowitą niezmienność przy pewnych kosztach wydajności.

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

Zasadniczo to, co próbujesz osiągnąć, sprawia, że ​​lista jest niezmienna. Jednak po oznaczeniu końcowego odwołania do wykazu oznacza to, że odniesienie nie może być wskazywane na inny obiekt listy inny niż ten.

Jeśli chcesz, aby ostateczna (niezmienna) tablica ArrayList została użyta, skorzystaj z metody narzędzia do kolekcjonowania klasy Collections.unmodifaibleList (list).