Bagaimana seseorang dapat membuat kelas Java tidak dapat diubah, apa kebutuhan kekekalan dan apakah ada keuntungan menggunakan ini?
java
string
immutability
JavaUser
sumber
sumber
@Immutable
anotasi ini dari jcabi-Jawaban:
Apa itu objek yang tidak bisa diubah?
Objek yang tidak dapat diubah adalah objek yang tidak akan berubah status setelah dibuat instance-nya.
Bagaimana cara membuat objek tidak berubah?
Secara umum, objek yang tidak dapat diubah dapat dibuat dengan mendefinisikan kelas yang anggotanya tidak ada yang terpapar, dan tidak memiliki penyetel.
Kelas berikut akan membuat objek yang tidak dapat diubah:
class ImmutableInt { private final int value; public ImmutableInt(int i) { value = i; } public int getValue() { return value; } }
Seperti yang bisa dilihat pada contoh di atas, nilai dari
ImmutableInt
hanya bisa disetel ketika objek dibuat, dan dengan hanya memiliki getter (getValue
), status objek tidak bisa diubah setelah pembuatan instance.Namun, harus berhati-hati bahwa semua objek yang direferensikan oleh objek juga harus tetap, atau status objek dapat diubah.
Misalnya, mengizinkan referensi ke larik atau
ArrayList
diperoleh melalui getter akan memungkinkan keadaan internal berubah dengan mengubah larik atau kumpulan:class NotQuiteImmutableList<T> { private final List<T> list; public NotQuiteImmutableList(List<T> list) { // creates a new ArrayList and keeps a reference to it. this.list = new ArrayList(list); } public List<T> getList() { return list; } }
Masalah dengan kode di atas adalah, bahwa
ArrayList
dapat diperoleh melaluigetList
dan dimanipulasi, yang mengarah ke keadaan objek itu sendiri yang akan diubah, oleh karena itu, tidak dapat diubah.// notQuiteImmutableList contains "a", "b", "c" List<String> notQuiteImmutableList= new NotQuiteImmutableList(Arrays.asList("a", "b", "c")); // now the list contains "a", "b", "c", "d" -- this list is mutable. notQuiteImmutableList.getList().add("d");
Salah satu cara untuk mengatasi masalah ini adalah dengan mengembalikan salinan larik atau koleksi saat dipanggil dari getter:
public List<T> getList() { // return a copy of the list so the internal state cannot be altered return new ArrayList(list); }
Apa keuntungan dari kekekalan?
Keuntungan dari kekekalan hadir dengan konkurensi. Sulit untuk mempertahankan kebenaran pada objek yang bisa berubah, karena beberapa utas mungkin mencoba mengubah status objek yang sama, yang menyebabkan beberapa utas melihat status berbeda dari objek yang sama, tergantung pada waktu pembacaan dan penulisan ke objek yang sama. obyek.
Dengan memiliki objek yang tidak dapat diubah, seseorang dapat memastikan bahwa semua utas yang melihat objek akan melihat status yang sama, karena status objek yang tidak dapat diubah tidak akan berubah.
sumber
return Collections.unmodifiableList(list);
dapat mengembalikan tampilan hanya-baca di daftar.final
. Jika tidak, itu dapat diperpanjang dengan metode penyetel (atau jenis metode mutasi lain dan bidang yang bisa berubah).final
jika kelas hanya memilikiprivate
bidang karena tidak dapat diakses dari subkelas.Selain jawaban yang sudah diberikan, saya merekomendasikan Anda membaca tentang immutability in Effective Java, 2nd Ed., Karena ada beberapa detail yang mudah terlewat (mis. Salinan defensif). Plus, Effective Java 2nd Ed. harus dibaca oleh setiap pengembang Java.
sumber
Anda membuat kelas tidak berubah seperti ini:
public final class Immutable { private final String name; public Immutable(String name) { this.name = name; } public String getName() { return this.name; } // No setter; }
Berikut adalah persyaratan untuk membuat kelas Java tidak dapat diubah:
final
(Sehingga kelas anak tidak dapat dibuat)final
(Sehingga kita tidak dapat mengubah nilainya setelah pembuatan objek)Kelas yang tidak dapat diubah berguna karena
- Kelas tersebut aman untuk thread.
- Mereka juga mengekspresikan sesuatu yang dalam tentang desain Anda: "Tidak dapat mengubah ini.", Jika diterapkan, itulah yang Anda butuhkan.
sumber
Kekekalan dapat dicapai terutama dengan dua cara:
final
atribut instance untuk menghindari penugasan ulangKeuntungan dari kekekalan adalah asumsi yang dapat Anda buat pada objek ini:
sumber
Kelas yang tidak dapat diubah tidak dapat menetapkan kembali nilai setelah dibuat instance-nya. Konstruktor menetapkan nilai ke variabel pribadinya. Sampai objek menjadi null, nilai tidak dapat diubah karena tidak tersedianya metode penyetel.
menjadi kekal harus memuaskan berikut,
/** * Strong immutability - by making class final */ public final class TestImmutablity { // make the variables private private String Name; //assign value when the object created public TestImmutablity(String name) { this.Name = name; } //provide getters to access values public String getName() { return this.Name; } }
Keuntungan: Objek yang tidak dapat diubah berisi nilai yang diinisialisasi sampai mati.
java-immutable-class-short-note
sumber
Kelas yang tidak dapat diubah adalah kelas yang objeknya tidak dapat diubah setelah dibuat.
Kelas yang tidak dapat diubah berguna untuk
Contoh
Kelas String
Contoh Kode
public final class Student { private final String name; private final String rollNumber; public Student(String name, String rollNumber) { this.name = name; this.rollNumber = rollNumber; } public String getName() { return this.name; } public String getRollNumber() { return this.rollNumber; } }
sumber
Bagaimana cara membuat kelas Java tidak dapat diubah?
Dari JDK 14+ yang memiliki JEP 359 , kita bisa menggunakan "
records
". Ini adalah cara paling sederhana dan bebas repot untuk membuat kelas Immutable.Kelas rekaman adalah pembawa transparan yang dangkal tidak berubah untuk sekumpulan bidang tetap yang dikenal sebagai rekaman
components
yang memberikanstate
deskripsi untuk rekaman tersebut. Masing-masingcomponent
memunculkanfinal
bidang yang menyimpan nilai yang diberikan danaccessor
metode untuk mengambil nilai. Nama bidang dan nama pengakses cocok dengan nama komponen.Mari pertimbangkan contoh membuat persegi panjang yang tidak bisa diubah
record Rectangle(double length, double width) {}
Tidak perlu mendeklarasikan konstruktor apa pun, tidak perlu mengimplementasikan metode sama & hashCode. Setiap Catatan membutuhkan nama dan deskripsi negara bagian.
var rectangle = new Rectangle(7.1, 8.9); System.out.print(rectangle.length()); // prints 7.1
Jika Anda ingin memvalidasi nilai selama pembuatan objek, kita harus secara eksplisit mendeklarasikan konstruktor.
public Rectangle { if (length <= 0.0) { throw new IllegalArgumentException(); } }
Badan record dapat mendeklarasikan metode statis, kolom statis, penginisialisasi statis, konstruktor, metode instance, dan jenis bertingkat.
Metode Instance
record Rectangle(double length, double width) { public double area() { return this.length * this.width; } }
bidang statis, metode
Karena status harus menjadi bagian dari komponen, kami tidak dapat menambahkan bidang contoh ke rekaman. Tapi, kita bisa menambahkan field dan metode statis:
record Rectangle(double length, double width) { static double aStaticField; static void aStaticMethod() { System.out.println("Hello Static"); } }
apa perlunya kekekalan dan apakah ada keuntungan menggunakan ini?
Jawaban yang diposting sebelumnya cukup baik untuk membenarkan kebutuhan akan kekekalan dan itu pro
sumber
Cara lain untuk membuat objek yang tidak dapat diubah menggunakan perpustakaan Immutables.org :
package info.sample; import java.util.List; import java.util.Set; import org.immutables.value.Value; @Value.Immutable public abstract class FoobarValue { public abstract int foo(); public abstract String bar(); public abstract List<Integer> buz(); public abstract Set<Long> crux(); }
package info.sample; import java.util.List; public class FoobarValueMain { public static void main(String... args) { FoobarValue value = ImmutableFoobarValue.builder() .foo(2) .bar("Bar") .addBuz(1, 3, 4) .build(); // FoobarValue{foo=2, bar=Bar, buz=[1, 3, 4], crux={}} int foo = value.foo(); // 2 List<Integer> buz = value.buz(); // ImmutableList.of(1, 3, 4) } }
sumber
Kelas yang tidak dapat diubah hanyalah kelas yang instansinya tidak dapat diubah.
Semua informasi yang terkandung dalam setiap contoh ditetapkan selama masa pakai objek, sehingga tidak ada perubahan yang dapat diamati.
Kelas yang tidak berubah lebih mudah untuk dirancang, diimplementasikan, dan digunakan daripada kelas yang bisa berubah.
Untuk membuat kelas tetap, ikuti lima aturan berikut:
Jangan berikan metode yang mengubah status objek
Pastikan kelas tidak dapat diperpanjang.
Buat semua bidang menjadi final.
Jadikan semua bidang pribadi.
Pastikan akses eksklusif ke semua komponen yang bisa berubah.
Objek yang tidak bisa diubah secara inheren aman untuk benang; mereka tidak membutuhkan sinkronisasi.
Objek yang tidak dapat diubah dapat dibagikan dengan bebas.
Objek yang tidak bisa diubah menjadi blok bangunan yang bagus untuk objek lain
sumber
@Jack, Memiliki bidang akhir dan penyetel di kelas tidak akan membuat kelas tidak dapat diubah. kata kunci terakhir hanya memastikan bahwa variabel tidak pernah ditetapkan ulang. Anda perlu mengembalikan salinan lengkap dari semua bidang dalam metode pengambil. Ini akan memastikan bahwa, setelah mendapatkan objek dari metode getter, keadaan internal objek tidak terganggu.
sumber
Sebagai penutur bahasa Inggris bukan penutur asli, saya tidak menyukai interpretasi umum dari "kelas yang tidak dapat diubah" menjadi "objek kelas yang dibangun tidak dapat diubah"; sebaliknya, saya sendiri cenderung menafsirkan bahwa sebagai "objek kelas itu sendiri tidak dapat diubah".
Yang mengatakan, "kelas yang tidak berubah" adalah sejenis objek yang tidak berubah. Bedanya saat menjawab apa manfaatnya. Untuk pengetahuan / interpretasi saya, kelas tetap mencegah objeknya dari modifikasi perilaku runtime.
sumber
Sebagian besar jawaban di sini bagus, dan beberapa menyebutkan aturannya tetapi saya merasa senang untuk menuliskan mengapa & kapan kita perlu mengikuti aturan ini. Demikian penjelasan di bawah ini
Dan tentu saja jika kita mencoba menggunakan Setter untuk variabel terakhir tersebut, compiler akan menampilkan error.
public class ImmutableClassExplored { public final int a; public final int b; /* OR Generally we declare all properties as private, but declaring them as public will not cause any issues in our scenario if we make them final public final int a = 109; public final int b = 189; */ ImmutableClassExplored(){ this. a = 111; this.b = 222; } ImmutableClassExplored(int a, int b){ this.a = a; this.b= b; } }
Apakah kita perlu mendeklarasikan kelas sebagai 'final'?
1. Hanya memiliki anggota primitif: Kami tidak memiliki masalah Jika kelas hanya memiliki anggota primitif, maka kami tidak perlu mendeklarasikan kelas sebagai final.
2.Memiliki Objek sebagai variabel anggota: Jika kita memiliki objek sebagai variabel anggota maka kita harus membuat anggota dari objek tersebut juga final. Berarti kita perlu melintasi jauh di bawah pohon dan menjadikan semua objek / primitif sebagai final yang mungkin tidak bisa dilakukan setiap saat. Jadi solusinya adalah membuat kelas final yang mencegah pewarisan. Jadi tidak ada pertanyaan tentang subclass overriding getter method.
sumber
@Value annotation of Lombok bisa digunakan untuk menghasilkan kelas yang tidak bisa diubah. Ini sesederhana kode di bawah ini.
@Value public class LombokImmutable { int id; String name; }
Sesuai dokumentasi di situs Lombok:
Contoh yang berfungsi sepenuhnya dapat ditemukan di sini.
sumber
record
bisa digunakan?