Saya menemukan kode berikut dalam basis kode yang saya kerjakan:
public final class ConfigurationService {
private static final ConfigurationService INSTANCE = new ConfigurationService();
private List providers;
private ConfigurationService() {
providers = new ArrayList();
}
public static void addProvider(ConfigurationProvider provider) {
INSTANCE.providers.add(provider);
}
...
INSTANCE
dideklarasikan sebagai final
. Mengapa objek bisa ditambahkan INSTANCE
? Bukankah itu seharusnya membatalkan penggunaan final. (Tidak).
Saya berasumsi jawabannya ada hubungannya dengan petunjuk dan ingatan, tetapi saya ingin tahu dengan pasti.
Jawaban:
final
cukup membuat referensi objek tidak bisa diubah. Objek yang ditunjukkannya tidak dapat diubah dengan melakukan ini.INSTANCE
tidak dapat merujuk ke objek lain, tetapi objek yang diacunya dapat berubah status.sumber
ConfigurationService
objek dan saya mencoba melakukan INSTANCE =deserializedConfigurationService
tidak akan diizinkan?INSTANCE
untuk merujuk ke objek lain. Tidak masalah darimana benda lain itu berasal. (NB ada satuINSTANCE
perClassLoader
yang telah memuat kelas ini. Anda secara teori dapat memuat kelas beberapa kali dalam satu JVM dan masing-masing terpisah. Tapi ini adalah poin teknis yang berbeda.)Menjadi final tidak sama dengan tidak berubah.
final != immutable
Kata
final
kunci digunakan untuk memastikan referensi tidak berubah (yaitu, referensi yang dimilikinya tidak dapat diganti dengan yang baru)Tetapi, jika atributnya adalah self dapat dimodifikasi, maka tidak masalah untuk melakukan apa yang baru saja Anda jelaskan.
Contohnya
class SomeHighLevelClass { public final MutableObject someFinalObject = new MutableObject(); }
Jika kita membuat instance kelas ini, kita tidak akan dapat menetapkan nilai lain ke atribut
someFinalObject
karena sudah final .Jadi ini tidak mungkin:
.... SomeHighLevelClass someObject = new SomeHighLevelClass(); MutableObject impostor = new MutableObject(); someObject.someFinal = impostor; // not allowed because someFinal is .. well final
Tetapi jika objek itu sendiri bisa berubah seperti ini:
class MutableObject { private int n = 0; public void incrementNumber() { n++; } public String toString(){ return ""+n; } }
Kemudian, nilai yang terkandung oleh objek yang bisa berubah itu dapat diubah.
SomeHighLevelClass someObject = new SomeHighLevelClass(); someObject.someFinal.incrementNumber(); someObject.someFinal.incrementNumber(); someObject.someFinal.incrementNumber(); System.out.println( someObject.someFinal ); // prints 3
Ini memiliki efek yang sama dengan postingan Anda:
public static void addProvider(ConfigurationProvider provider) { INSTANCE.providers.add(provider); }
Di sini Anda tidak mengubah nilai INSTANCE, Anda mengubah status internalnya (melalui, metode provider.add)
jika Anda ingin mencegah definisi kelas harus diubah seperti ini:
public final class ConfigurationService { private static final ConfigurationService INSTANCE = new ConfigurationService(); private List providers; private ConfigurationService() { providers = new ArrayList(); } // Avoid modifications //public static void addProvider(ConfigurationProvider provider) { // INSTANCE.providers.add(provider); //} // No mutators allowed anymore :) ....
Tapi, itu mungkin tidak masuk akal :)
Omong-omong, Anda juga harus menyinkronkan akses ke sana pada dasarnya untuk alasan yang sama.
sumber
Kunci kesalahpahaman ada di judul pertanyaan Anda. Bukan objek yang final, melainkan variabelnya . Nilai variabel tidak bisa berubah, tetapi data di dalamnya bisa.
Ingatlah selalu bahwa ketika Anda mendeklarasikan variabel tipe referensi, nilai variabel itu adalah referensi, bukan objek.
sumber
final hanya berarti referensi tidak dapat diubah. Anda tidak dapat menetapkan ulang INSTANCE ke referensi lain jika itu dinyatakan sebagai final. Keadaan internal objek masih bisa berubah.
final ConfigurationService INSTANCE = new ConfigurationService(); ConfigurationService anotherInstance = new ConfigurationService(); INSTANCE = anotherInstance;
akan memunculkan kesalahan kompilasi
sumber
Sumber
Berikut panduan untuk membuat objek tidak berubah .
sumber
Final dan kekal bukanlah hal yang sama. Final berarti referensi tidak dapat dialihkan sehingga Anda tidak dapat mengatakannya
Tidak dapat diubah berarti objek itu sendiri tidak dapat dimodifikasi. Contohnya adalah
java.lang.String
kelas. Anda tidak dapat mengubah nilai string.sumber
Java tidak memiliki konsep kekekalan yang dibangun ke dalam bahasa. Tidak ada cara untuk menandai metode sebagai mutator. Oleh karena itu bahasa tidak memiliki cara untuk memaksakan ketetapan objek.
sumber