Bayangkan saya memiliki kelas ini:
public class Test
{
private String[] arr = new String[]{"1","2"};
public String[] getArr()
{
return arr;
}
}
Sekarang, saya memiliki kelas lain yang menggunakan kelas di atas:
Test test = new Test();
test.getArr()[0] ="some value!"; //!!!
Jadi ini masalahnya: Saya telah mengakses bidang pribadi kelas dari luar! Bagaimana saya bisa mencegah ini? Maksud saya, bagaimana saya bisa membuat array ini tidak berubah? Apakah ini berarti bahwa dengan setiap metode pengambil Anda dapat bekerja dengan cara Anda untuk mengakses bidang pribadi? (Saya tidak ingin ada perpustakaan seperti Guava. Saya hanya perlu tahu cara yang tepat untuk melakukan ini).
final
memang mencegah modifikasi lapangan . Namun, mencegah modifikasi yangObject
dimaksud oleh suatu bidang lebih rumit.Jawaban:
Anda harus mengembalikan salinan array Anda.
sumber
Unmodifiable List
.Jika Anda dapat menggunakan Daftar alih-alih array, Koleksi menyediakan daftar yang tidak dapat dimodifikasi :
sumber
Collections.unmodifiableList(list)
sebagai tugas ke bidang, untuk memastikan bahwa daftar tidak diubah oleh kelas itu sendiri.String
adanya, tetapi jika mereka bisa berubah, sesuatu mungkin harus dilakukan untuk mencegah penelepon mengubahnya.Pengubah
private
hanya melindungi bidang itu sendiri dari akses dari kelas lain, tetapi bukan referensi objek oleh bidang ini. Jika Anda perlu melindungi objek yang dirujuk, tapi jangan berikan. Perubahanuntuk:
atau untuk
sumber
The
Collections.unmodifiableList
telah disebutkan - yangArrays.asList()
anehnya tidak! Solusi saya juga menggunakan daftar dari luar dan membungkus array sebagai berikut:Masalah dengan menyalin array adalah: jika Anda melakukannya setiap kali Anda mengakses kode dan array besar, Anda pasti akan membuat banyak pekerjaan untuk pemulung. Jadi salinannya adalah pendekatan yang sederhana tetapi sangat buruk - saya akan mengatakan "murah", tetapi memori mahal! Terutama ketika Anda memiliki lebih dari 2 elemen.
Jika Anda melihat kode sumber
Arrays.asList
danCollections.unmodifiableList
sebenarnya tidak banyak yang dibuat. Yang pertama hanya membungkus array tanpa menyalinnya, yang kedua hanya membungkus daftar, membuat perubahan itu tidak tersedia.sumber
immutableList
!Arrays.asList
danCollections.unmodifiableList
operasi mungkin lebih murah untuk array yang lebih besar. Mungkin seseorang dapat menghitung berapa banyak elemen yang diperlukan, tetapi saya telah melihat kode di-loop dengan array berisi ribuan elemen yang disalin hanya untuk mencegah modifikasi - itu gila!Anda juga bisa menggunakan
ImmutableList
mana yang harus lebih baik dari standarunmodifiableList
. Kelas adalah bagian dari perpustakaan Guava yang dibuat oleh Google.Berikut uraiannya:
Berikut ini adalah contoh sederhana cara menggunakannya:
sumber
Test
kelas untuk membiarkan daftar yang dikembalikan tidak berubah . Anda perlu memastikan bahwaImmutableList
itu dikembalikan, dan bahwa elemen-elemen dari daftar juga tidak berubah. Kalau tidak, solusi saya harus aman juga.pada titik pandang ini Anda harus menggunakan salinan array sistem:
sumber
clone
, dan tidak sesingkat itu.Anda dapat mengembalikan salinan data. Penelepon yang memilih untuk mengubah data hanya akan mengubah salinan
sumber
Inti masalahnya adalah Anda mengembalikan pointer ke objek yang bisa diubah. Ups. Entah Anda membuat objek tidak berubah (solusi daftar tidak dapat dimodifikasi) atau Anda mengembalikan salinan objek.
Secara umum, finalitas objek tidak melindungi objek dari perubahan jika mereka bisa berubah. Dua masalah ini adalah "mencium sepupu."
sumber
Mengembalikan daftar yang tidak dapat dimodifikasi adalah ide yang bagus. Tetapi daftar yang dibuat tidak dapat dimodifikasi selama panggilan ke metode pengambil masih dapat diubah oleh kelas, atau kelas yang diturunkan dari kelas.
Alih-alih, Anda harus menjelaskan kepada siapa pun yang memperluas kelas bahwa daftar tidak boleh dimodifikasi.
Jadi, dalam contoh Anda ini dapat mengarah ke kode berikut:
Dalam contoh di atas saya telah membuat
STRINGS
bidang publik, pada prinsipnya Anda bisa menghilangkan panggilan metode, karena nilai sudah diketahui.Anda juga bisa menetapkan string ke
private final List<String>
bidang yang tidak dapat dimodifikasi selama konstruksi instance kelas. Menggunakan argumen konstanta atau instantiasi (dari konstruktor) tergantung pada desain kelas.sumber
Ya, Anda harus mengembalikan salinan array:
sumber