Apa alasan mengapa Java tidak mengizinkan kami melakukannya
private T[] elements = new T[initialCapacity];
Saya bisa mengerti. NET tidak mengizinkan kami untuk melakukan itu, seperti dalam. NET Anda memiliki tipe nilai yang pada saat run-time dapat memiliki ukuran yang berbeda, tetapi di Jawa semua jenis T akan menjadi referensi objek, sehingga memiliki ukuran yang sama ( koreksi saya jika saya salah).
Apa alasannya?
java
generics
type-erasure
melahap elysium
sumber
sumber
Jawaban:
Itu karena array Java (tidak seperti generik) berisi, pada saat runtime, informasi tentang tipe komponennya. Jadi, Anda harus tahu tipe komponen saat membuat array. Karena Anda tidak tahu apa
T
itu saat runtime, Anda tidak bisa membuat array.sumber
ArrayList <SomeType>
caranya?new ArrayList<SomeType>()
? Tipe generik tidak mengandung parameter tipe saat runtime. Parameter tipe tidak digunakan dalam pembuatan. Tidak ada perbedaan dalam kode yang dihasilkan olehnew ArrayList<SomeType>()
ataunew ArrayList<String>()
ataunew ArrayList()
sama sekali.ArrayList<T>
kerjanya dengan 'private T[] myArray
. Di suatu tempat dalam kode, itu harus memiliki array tipe T generik, jadi bagaimana?T[]
. Ini memiliki larik tipe runtimeObject[]
, dan 1) kode sumber berisi variabelObject[]
(ini adalah bagaimana itu dalam sumber Java Java terbaru); atau 2) kode sumber berisi variabel tipeT[]
, yang merupakan kebohongan, tetapi tidak menyebabkan masalah karenaT
dihapus di dalam ruang lingkup kelas.Mengutip:
(Saya percaya itu adalah Neal Gafter , tetapi saya tidak yakin)
Lihat dalam konteks di sini: http://forums.sun.com/thread.jspa?threadID=457033&forumID=316
sumber
new T()
. Setiap array di Jawa, dengan desain, menyimpan tipe komponen (yaituT.class
) di dalamnya; Oleh karena itu Anda memerlukan kelas T saat runtime untuk membuat array seperti itu.new Box<?>[n]
, yang kadang-kadang cukup, meskipun itu tidak membantu dalam contoh Anda.Box<String>[] bsa = new Box<String>[3];
apakah ada perubahan di java-8 dan ke atas saya berasumsi?Dengan gagal memberikan solusi yang layak, Anda hanya berakhir dengan IMHO sesuatu yang lebih buruk.
Pekerjaan umum di sekitar adalah sebagai berikut.
diganti dengan (dengan asumsi T memperluas Object dan bukan kelas lain)
Saya lebih suka contoh pertama, tetapi lebih banyak tipe akademis yang lebih suka contoh kedua, atau lebih suka tidak memikirkannya.
Sebagian besar contoh mengapa Anda tidak bisa hanya menggunakan Obyek [] sama-sama berlaku untuk Daftar atau Koleksi (yang didukung), jadi saya melihatnya sebagai argumen yang sangat buruk.
Catatan: ini adalah salah satu alasan perpustakaan Koleksi itu sendiri tidak mengkompilasi tanpa peringatan. Jika Anda menggunakan case ini tidak dapat didukung tanpa peringatan, ada sesuatu yang pada dasarnya rusak dengan model generik IMHO.
sumber
String[]
(atau jika Anda menyimpannya di bidang yang dapat diakses secara publik dari tipeT[]
, dan seseorang mengambilnya), maka mereka akan mendapatkan ClassCastException.T[] ts = (T[]) new Object[n];
itu ide yang buruk: stackoverflow.com/questions/21577493/...T[] ts = new T[n];
itu adalah contoh yang valid. Saya akan memilih karena jawaban dia dapat menyebabkan masalah dan kebingungan kepada devs lain dan juga di luar topik. Juga, saya akan berhenti berkomentar tentang ini.Array adalah Covarian
Baris terakhir ini akan mengkompilasi dengan baik, tetapi jika kita menjalankan kode ini, kita akan mendapatkan
ArrayStoreException
karena kita mencoba untuk menempatkan ganda ke dalam array integer. Fakta bahwa kita mengakses array melalui referensi Number tidak relevan di sini, yang penting array adalah array integer.Ini berarti bahwa kita dapat mengelabui kompiler, tetapi kita tidak dapat menipu sistem tipe run-time. Dan ini terjadi karena array adalah apa yang kita sebut tipe yang dapat diverifikasi. Ini berarti bahwa pada saat run-time Java tahu bahwa array ini sebenarnya dipakai sebagai array integer yang kebetulan diakses melalui referensi tipe
Number[]
.Jadi, seperti yang bisa kita lihat, satu hal adalah jenis objek yang sebenarnya, satu hal lagi adalah jenis referensi yang kita gunakan untuk mengaksesnya, bukan?
Masalah dengan Java Generics
Sekarang, masalah dengan tipe generik di Jawa adalah bahwa informasi tipe untuk parameter tipe dibuang oleh kompiler setelah kompilasi kode dilakukan; oleh karena itu informasi jenis ini tidak tersedia pada saat dijalankan. Proses ini disebut tipe erasure . Ada alasan bagus untuk mengimplementasikan obat generik seperti ini di Jawa, tapi itu cerita panjang, dan itu ada hubungannya dengan kompatibilitas biner dengan kode yang sudah ada sebelumnya.
Mari pertimbangkan sekarang kode tidak aman berikut:
Jika kompiler Java tidak menghentikan kita dari melakukan ini, sistem tipe run-time tidak dapat menghentikan kita juga, karena pada saat run time, tidak ada cara untuk menentukan bahwa daftar ini seharusnya hanya menjadi daftar bilangan bulat saja. Run-time Java akan membiarkan kita memasukkan apa pun yang kita inginkan ke dalam daftar ini, padahal seharusnya hanya berisi bilangan bulat, karena ketika dibuat, itu dinyatakan sebagai daftar bilangan bulat. Itu sebabnya kompiler menolak baris nomor 4 karena tidak aman dan jika dibiarkan bisa mematahkan asumsi sistem tipe.
Dengan demikian, para perancang Java memastikan bahwa kita tidak dapat membodohi kompiler. Jika kita tidak dapat membodohi kompiler (seperti yang dapat kita lakukan dengan array) maka kita juga tidak bisa menipu sistem tipe run-time.
Karena itu, kami mengatakan bahwa tipe generik tidak dapat diverifikasi, karena pada saat dijalankan kami tidak dapat menentukan sifat sebenarnya dari tipe generik.
Saya melewatkan beberapa bagian dari jawaban ini, Anda dapat membaca artikel lengkap di sini: https://dzone.com/articles/covariance-and-contravariance
sumber
Alasan ini tidak mungkin adalah bahwa Java mengimplementasikan Generiknya murni pada tingkat kompiler, dan hanya ada satu file kelas yang dihasilkan untuk setiap kelas. Ini disebut Penghapusan Jenis .
Saat runtime, kelas yang dikompilasi perlu menangani semua penggunaannya dengan bytecode yang sama. Jadi,
new T[capacity]
sama sekali tidak tahu tipe apa yang perlu dipakai.sumber
Jawabannya sudah diberikan tetapi jika Anda sudah memiliki Mesin Virtual maka Anda dapat melakukan ini:
Semoga, saya bisa membantu, Ferdi265
sumber
T[] ts = t.clone(); for (int i=0; i<ts.length; i++) ts[i] = null;
.T[] t
, maka itu akan menjadi(T[]) Array.newInstance(t.getClass().getComponentType(), length);
. Saya memang menghabiskan beberapa waktu untuk mencari tahugetComponentType()
. Semoga ini bisa membantu orang lain.t.clone()
tidak akan kembaliT[]
. Karenat
tidak Array dalam jawaban ini.Alasan utama adalah karena fakta bahwa array di Jawa adalah kovarian.
Ada ikhtisar yang bagus di sini .
sumber
String[]
keObject
dan menyimpanInteger
di dalamnya. Jadi mereka harus menambahkan pemeriksaan runtime type untuk array store (ArrayStoreException
) karena masalah tidak dapat ditangkap pada waktu kompilasi. (Kalau tidak,Integer
sebenarnya bisa terjebak dalamString[]
, dan Anda akan mendapatkan kesalahan ketika Anda mencoba mengambilnya, yang akan mengerikan.) ...Object
seharusnyaObject[]
di komentar pertama saya.Saya suka jawaban yang diberikan secara tidak langsung oleh Gafter . Namun, saya mengusulkan itu salah. Saya mengubah sedikit kode Gafter. Itu mengkompilasi dan berjalan untuk sementara waktu kemudian meledak di mana Gafter memperkirakan itu akan terjadi
Outputnya adalah
Jadi menurut saya Anda dapat membuat tipe array generik di java. Apakah saya salah paham pertanyaannya?
sumber
Saya tahu saya sedikit terlambat ke pesta di sini, tetapi saya pikir saya mungkin bisa membantu para googler di masa depan karena tidak ada jawaban yang memperbaiki masalah saya. Jawaban Ferdi265 sangat membantu.
Saya mencoba membuat daftar Linked saya sendiri, jadi kode berikut ini berfungsi untuk saya:
Dalam metode toArray () terletak cara untuk membuat array tipe generik untuk saya:
sumber
Dalam kasus saya, saya hanya ingin berbagai tumpukan, seperti ini:
Karena ini tidak mungkin, saya menggunakan yang berikut sebagai solusi:
Jelek, tapi Jawa senang.
Catatan: seperti yang disebutkan oleh BrainSlugs83 dalam komentar pertanyaan, sangat mungkin untuk memiliki array generik di .NET
sumber
Dari tutorial Oracle :
Bagi saya, itu terdengar sangat lemah. Saya pikir siapa pun yang memiliki pemahaman generik yang memadai, akan baik-baik saja, dan bahkan berharap, bahwa ArrayStoredException tidak dilemparkan dalam kasus seperti itu.
sumber
Tentunya harus ada cara yang baik di sekitarnya (mungkin menggunakan refleksi), karena menurut saya itulah yang sebenarnya
ArrayList.toArray(T[] a)
terjadi. Saya mengutip:Jadi salah satu cara mengatasinya adalah dengan menggunakan fungsi ini yaitu membuat
ArrayList
objek yang Anda inginkan dalam array, kemudian gunakantoArray(T[] a)
untuk membuat array aktual. Ini tidak akan cepat, tetapi Anda tidak menyebutkan persyaratan Anda.Jadi, adakah yang tahu bagaimana
toArray(T[] a)
penerapannya?sumber
Array.newInstance()
. Anda akan menemukan bahwa disebutkan dalam banyak pertanyaan yang menanyakan cara membuat array dengan tipe yang tidak dikenal pada waktu kompilasi. Tetapi OP secara khusus menanyakan mengapa Anda tidak dapat menggunakannew T[]
sintaksis, yang merupakan pertanyaan yang berbedaItu karena generik ditambahkan ke java setelah mereka membuatnya, jadi itu agak kikuk karena pembuat asli java berpikir bahwa ketika membuat array tipe akan ditentukan dalam pembuatannya. Jadi itu tidak bekerja dengan obat generik sehingga Anda harus melakukan E [] array = (E []) Obyek baru [15]; Ini mengkompilasi tetapi memberi peringatan.
sumber
Jika kita tidak dapat membuat instance array generik, mengapa bahasa tersebut memiliki tipe array generik? Apa gunanya memiliki tipe tanpa objek?
Satu-satunya alasan yang dapat saya pikirkan adalah varargs -
foo(T...)
. Kalau tidak, mereka bisa sepenuhnya menggosok jenis array generik. (Yah, mereka tidak benar-benar harus menggunakan array untuk varargs, karena vararg tidak ada sebelum 1.5 . Itu mungkin kesalahan lain.)Jadi itu bohong, Anda bisa instantiate array generik, melalui varargs!
Tentu saja, masalah dengan array generik masih nyata, misalnya
Kita dapat menggunakan contoh ini untuk benar-benar menunjukkan bahaya array generik .
Di sisi lain, kami telah menggunakan vararg generik selama satu dekade, dan langit belum jatuh. Jadi kita bisa berargumen bahwa masalahnya dibesar-besarkan; ini bukan masalah besar. Jika pembuatan larik generik eksplisit diizinkan, kami akan memiliki bug di sana-sini; tapi kita sudah terbiasa dengan masalah penghapusan, dan kita bisa hidup dengannya.
Dan kita dapat menunjuk untuk
foo2
membantah klaim bahwa spek itu menjauhkan kita dari masalah yang mereka klaim untuk menjaga kita. Jika Sun memiliki lebih banyak waktu dan sumber daya untuk 1,5 , saya percaya mereka bisa mencapai resolusi yang lebih memuaskan.sumber
Seperti yang telah disebutkan orang lain, tentu saja Anda dapat membuat melalui beberapa trik .
Tapi itu tidak disarankan.
Karena tipe penghapusan dan yang lebih penting
covariance
array dalam yang hanya memungkinkan array subtipe dapat ditugaskan ke array supertipe, yang memaksa Anda untuk menggunakan tipe cast eksplisit ketika mencoba untuk mendapatkan nilai kembali menyebabkan run-timeClassCastException
yang merupakan salah satu tujuan utama yang coba dihilangkan oleh obat generik: Pemeriksaan tipe yang lebih kuat pada waktu kompilasi .Contoh lebih langsung dapat ditemukan di Java Efektif: Item 25 .
covariance : array tipe S [] adalah subtipe dari T [] jika S adalah subtipe dari T
sumber
Jika kelas menggunakan sebagai tipe parameter, ia dapat mendeklarasikan array bertipe T [], tetapi ia tidak dapat langsung membuat array seperti itu. Sebagai gantinya, pendekatan umum adalah untuk instantiate array dari tipe Object [], dan kemudian membuat cast penyempitan untuk mengetik T [], seperti yang ditunjukkan pada berikut ini:
sumber
Coba ini:
sumber