Diberikan kode berikut:
public static void main(String[] args) {
record Foo(int[] ints){}
var ints = new int[]{1, 2};
var foo = new Foo(ints);
System.out.println(foo); // Foo[ints=[I@6433a2]
System.out.println(new Foo(new int[]{1,2}).equals(new Foo(new int[]{1,2}))); // false
System.out.println(new Foo(ints).equals(new Foo(ints))); //true
System.out.println(foo.equals(foo)); // true
}
Tampaknya, jelas bahwa array toString
, equals
metode digunakan (bukan metode statis Arrays::equals
,, Arrays::deepEquals
atau Array::toString
).
Jadi saya kira Java 14 Records ( JEP 359 ) tidak berfungsi dengan baik dengan array, metode masing-masing harus dihasilkan dengan IDE (yang setidaknya di IntelliJ, secara default menghasilkan metode "berguna", yaitu mereka menggunakan metode statis dalam Arrays
).
Atau adakah solusi lain?
java
arrays
java-14
java-record
pengguna140547
sumber
sumber
List
bukan array?toString()
,equals()
danhashCode()
metode rekor diimplementasikan menggunakan referensi invokedynamic. . Jika hanya kelas yang dikompilasi setara bisa lebih dekat dengan apa yang dilakukan metodeArrays.deepToString
ini dalam metode kelebihan beban pribadinya hari ini, itu mungkin telah dipecahkan untuk kasus primitif.Object
, karena itu bisa terjadi dengan kelas yang ditentukan pengguna juga. mis salah sama denganinvokedynamic
sama sekali tidak ada hubungannya dengan pemilihan semantik; indy adalah detail implementasi murni di sini. Kompilator dapat memancarkan bytecode untuk melakukan hal yang sama; ini hanya cara yang lebih efisien dan fleksibel untuk sampai ke sana. Itu dibahas secara luas selama desain catatan apakah akan menggunakan semantik kesetaraan yang lebih bernuansa (seperti kesetaraan yang mendalam untuk array), tetapi ini ternyata menyebabkan jauh lebih banyak masalah daripada yang seharusnya dipecahkan.Jawaban:
Array Java menimbulkan beberapa tantangan untuk rekaman, dan ini menambah sejumlah kendala pada desain. Array bisa berubah, dan semantik kesetaraan mereka (diwarisi dari Object) adalah dengan identitas, bukan konten.
Masalah mendasar dengan contoh Anda adalah bahwa Anda berharap bahwa
equals()
pada array berarti kesetaraan konten, bukan kesetaraan referensi. Semantik (default)equals()
untuk catatan didasarkan pada kesetaraan komponen; dalam contoh, duaFoo
catatan yang berisi array yang berbeda yang berbeda, dan catatan berperilaku dengan benar. Masalahnya adalah Anda hanya berharap perbandingan kesetaraannya berbeda.Yang mengatakan, Anda dapat mendeklarasikan catatan dengan semantik yang Anda inginkan, itu hanya membutuhkan lebih banyak pekerjaan, dan Anda mungkin merasa terlalu banyak bekerja. Berikut catatan yang melakukan apa yang Anda inginkan:
Apa yang dilakukan adalah salinan defensif di jalan (di konstruktor) dan di jalan keluar (di accessor), serta menyesuaikan semantik kesetaraan untuk menggunakan konten array. Ini mendukung invarian, diperlukan dalam superclass
java.lang.Record
, yang "memisahkan catatan ke dalam komponennya, dan merekonstruksi komponen menjadi catatan baru, menghasilkan rekor yang sama."Anda mungkin berkata, "Tapi itu terlalu banyak pekerjaan, saya ingin menggunakan catatan sehingga saya tidak perlu mengetik semua itu." Tetapi, catatan bukan terutama alat sintaksis (meskipun secara sintaksis lebih menyenangkan), catatan adalah alat semantik: catatan adalah tupel nominal . Sebagian besar waktu, sintaks kompak juga menghasilkan semantik yang diinginkan, tetapi jika Anda ingin semantik yang berbeda, Anda harus melakukan beberapa pekerjaan tambahan.
sumber
List< Integer >
solusiPenanganan Masalah: Gunakan a
List
dariInteger
objek (List< Integer >
) daripada array primitif (int[]
).Dalam contoh ini, saya instantiate daftar kelas yang tidak ditentukan yang tidak dapat dimodifikasi dengan menggunakan
List.of
fitur yang ditambahkan ke Java 9. Anda bisa juga menggunakanArrayList
, untuk daftar yang dapat dimodifikasi yang didukung oleh array.sumber
Penanganan masalah: Buat
IntArray
kelas dan bungkusint[]
.Tidak sempurna, karena Anda sekarang harus menelepon
foo.getInts()
alih-alihfoo.ints()
, tetapi semua yang lain berfungsi seperti yang Anda inginkan.Keluaran
sumber
record
dapat terdiri dari banyak bidang, dan hanya bidang array yang dibungkus seperti ini.List
yang menyediakan jenis pembungkus yang mungkin dicari seseorang dengan solusi seperti yang diusulkan di sini. Atau apakah Anda menganggap itu bisa menjadi overhead untuk kasus penggunaan seperti itu?int[]
, maka aList<Integer>
tidak sama, untuk setidaknya dua alasan: 1) Daftar ini menggunakan lebih banyak memori, dan 2) Tidak ada konversi bawaan di antara mereka.Integer[]
🡘List<Integer>
cukup mudah (toArray(...)
danArrays.asList(...)
), tetapiint[]
🡘List<Integer>
membutuhkan lebih banyak pekerjaan, dan konversi membutuhkan waktu, jadi itu adalah sesuatu yang tidak ingin Anda lakukan sepanjang waktu. Jika Anda memilikiint[]
dan ingin menyimpannya dalam rekaman (dengan barang lain, jika tidak mengapa menggunakan catatan), dan membutuhkannya sebagaiint[]
, lalu mengonversi setiap kali Anda membutuhkannya adalah salah.Arrays.equals
,Arrays.toString
atasList
implementasi yang digunakan saat menggantiint[]
seperti yang disarankan dalam jawaban lainnya. (Dengan asumsi kedua ini adalah penyelesaian masalah.)