Sejak Java 5, kami sudah memiliki tinju / unboxing dari jenis primitif sehingga int
dibungkus menjadi java.lang.Integer
, dan seterusnya dan seterusnya.
Saya melihat banyak proyek Java baru akhir-akhir ini (yang pasti membutuhkan JRE setidaknya versi 5, jika tidak 6) yang menggunakan int
daripada java.lang.Integer
, meskipun jauh lebih nyaman untuk menggunakan yang terakhir, karena memiliki beberapa metode pembantu untuk mengkonversi untuk long
nilai et al.
Mengapa beberapa masih menggunakan tipe primitif di Jawa? Apakah ada manfaat nyata?
java
primitive
primitive-types
autoboxing
jdk1.5
Naftuli Kay
sumber
sumber
new IntegeR(5) == new Integer(5)
harus oleh aturan, evaluasi menjadi false.Jawaban:
Dalam Java Efektif Joshua Bloch , Item 5: "Hindari membuat objek yang tidak perlu", ia memposting contoh kode berikut:
dan butuh 43 detik untuk berjalan. Mengambil Long ke primitif membuatnya turun menjadi 6,8 detik ... Jika itu indikasi mengapa kita menggunakan primitif.
Kurangnya kesetaraan nilai asli juga merupakan masalah (
.equals()
cukup bertele-tele dibandingkan dengan==
)untuk biziclop:
Hasil dalam:
EDIT Mengapa (3) kembali
true
dan (4) kembalifalse
?Karena mereka adalah dua objek yang berbeda. 256 bilangan bulat yang paling dekat dengan nol [-128; 127] di-cache oleh JVM, jadi mereka mengembalikan objek yang sama untuk mereka. Di luar rentang itu, mereka tidak di-cache, jadi objek baru dibuat. Untuk membuat segalanya menjadi lebih rumit, JLS menuntut setidaknya 256 bobot terbang di-cache. Implementer JVM dapat menambahkan lebih banyak jika mereka inginkan, yang berarti ini dapat berjalan pada sistem di mana 1024 terdekat di-cache dan semuanya kembali benar ... #awkward
sumber
i
dinyatakanLong
juga!==
operator melakukan perbandingan identitas referensi padaInteger
ekspresi dan perbandingan kesetaraan nilai padaint
ekspresi.Integer.equals()
ada karena alasan ini. Anda tidak boleh menggunakan==
untuk membandingkan nilai dalam tipe non-primitif apa pun. Ini adalah Java 101.Autounboxing dapat menyebabkan sulit untuk menemukan NPE
Dalam kebanyakan situasi penugasan nol
in
jauh lebih jelas daripada di atas.sumber
Jenis kotak memiliki kinerja yang lebih buruk dan membutuhkan lebih banyak memori.
sumber
Tipe primitif:
Sekarang evaluasi:
Ini
true
. Sangat mengejutkan. Sekarang coba jenis kotak:Sekarang evaluasi:
Ini
false
. Mungkin. Tergantung pada runtime. Apakah itu alasan yang cukup?sumber
Selain masalah kinerja dan memori, saya ingin memunculkan masalah lain:
List
Antarmuka akan rusak tanpaint
.Masalahnya adalah
remove()
metode kelebihan beban (remove(int)
vs.remove(Object)
).remove(Integer)
akan selalu memutuskan untuk memanggil yang terakhir, jadi Anda tidak dapat menghapus elemen dengan indeks.Di sisi lain, ada jebakan ketika mencoba untuk menambah dan menghapus
int
:sumber
Vector
sudahremoveElementAt(int)
sejak awal.remove(int)
diperkenalkan dengan kerangka koleksi di Jawa 1.2.List
API dirancang, Generics maupun Autoboxing tidak ada, jadi tidak ada peluang untuk mencampurremove(int)
danremove(Object)
...Bisakah Anda benar-benar membayangkan a
sebaliknya dengan java.lang.Integer? Java.lang.Integer tidak dapat diubah, sehingga setiap kenaikan putaran loop akan membuat objek java baru di heap, daripada hanya menambah int pada stack dengan instruksi JVM tunggal. Performanya akan sangat kejam.
Saya akan sangat tidak setuju bahwa ini adalah mode yang nyaman untuk menggunakan java.lang.Integer daripada int. Di sisi lain. Autoboxing berarti bahwa Anda dapat menggunakan int di mana Anda akan dipaksa untuk menggunakan Integer, dan kompiler java menangani memasukkan kode untuk membuat objek Integer baru untuk Anda. Autoboxing adalah tentang memungkinkan Anda untuk menggunakan int di mana Integer diharapkan, dengan kompiler memasukkan konstruksi objek yang relevan. Ini sama sekali tidak menghilangkan atau mengurangi kebutuhan int di tempat pertama. Dengan autoboxing Anda mendapatkan yang terbaik dari kedua dunia. Anda mendapatkan Integer yang dibuat untuk Anda secara otomatis ketika Anda membutuhkan objek java berbasis heap, dan Anda mendapatkan kecepatan dan efisiensi int ketika Anda hanya melakukan perhitungan aritmatika dan lokal.
sumber
Tipe primitif jauh lebih cepat:
Integer (semua Bilangan dan juga String a) adalah kekal ketik: sekali dibuat tidak dapat diubah. Jika
i
itu Integer, daripadai++
akan membuat objek Integer baru - jauh lebih mahal dalam hal memori dan prosesor.sumber
i++
pada variabel lain, jadi Integer cukup tidak dapat diubah untuk dapat melakukan ini (atau setidaknya inii++
harus tetap membuat objek Integer baru). (Dan nilai-nilai primitif juga tidak dapat berubah - Anda hanya tidak berkomentar karena ini bukan objek.)++
merupakan herring merah di sini. Bayangkan Java ditingkatkan ke operator dukungan overloading dalam cara yang sangat sederhana, sehingga jika kelas (sepertiInteger
memiliki sebuah metodeplus
, maka Anda bisa menulisi + 1
bukani.plus(1)
. Dan menganggap juga bahwa compiler cukup pintar untuk memperluasi++
kei = i + 1
. Sekarang Anda bisa mengatakani++
dan secara efektif "meningkatkan variabel i" tanpaInteger
bisa berubahPertama dan terpenting, kebiasaan. Jika Anda telah mengkodekan di Jawa selama delapan tahun, Anda mengumpulkan banyak inersia. Mengapa berubah jika tidak ada alasan kuat untuk melakukannya? Ini bukan seolah-olah menggunakan kotak primitif datang dengan kelebihan tambahan.
Alasan lainnya adalah untuk menegaskan bahwa
null
itu bukan opsi yang valid. Tidak ada gunanya dan menyesatkan untuk menyatakan jumlah dua angka atau variabel loop sebagaiInteger
.Ada aspek kinerja juga, sementara perbedaan kinerja tidak kritis dalam banyak kasus (meskipun ketika itu, itu sangat buruk), tidak ada yang suka menulis kode yang dapat ditulis dengan mudah dengan cara yang lebih cepat kita sudah biasanya.
sumber
By the way, Smalltalk hanya memiliki objek (tidak primitif), namun mereka telah mengoptimalkan bilangan bulat kecil mereka (menggunakan tidak semua 32 bit, hanya 27 atau semacamnya) untuk tidak mengalokasikan ruang heap, tetapi cukup gunakan pola bit khusus. Juga objek umum lainnya (true, false, null) memiliki pola bit khusus di sini.
Jadi, setidaknya pada JVM 64-bit (dengan namespace pointer 64 bit) harus dimungkinkan untuk tidak memiliki objek Integer, Character, Byte, Short, Boolean, Float (dan Long kecil) sama sekali (terlepas dari ini dibuat secara eksplisit
new ...()
), hanya pola bit khusus, yang dapat dimanipulasi oleh operator normal dengan cukup efisien.sumber
Saya tidak percaya tidak ada yang menyebutkan apa yang saya pikir adalah alasan paling penting: "int" begitu, jadi lebih mudah untuk mengetik daripada "Integer". Saya pikir orang meremehkan pentingnya sintaksis singkat. Kinerja sebenarnya bukan alasan untuk menghindarinya karena sebagian besar waktu ketika seseorang menggunakan angka ada dalam indeks lingkaran, dan menambah dan membandingkan biaya-biaya itu tidak ada dalam loop non-sepele (apakah Anda menggunakan int atau Integer).
Alasan lain yang diberikan adalah bahwa Anda bisa mendapatkan NPE tapi itu sangat mudah untuk dihindari dengan tipe kotak (dan dijamin akan dihindari selama Anda selalu menginisialisasi mereka ke nilai-nilai non-nol).
Alasan lainnya adalah bahwa (Long baru (1000)) == (new Long (1000)) adalah salah, tetapi itu hanyalah cara lain untuk mengatakan bahwa ".equals" tidak memiliki dukungan sintaksis untuk jenis kotak (tidak seperti operator <,> , =, dll), jadi kita kembali ke alasan "sintaksis yang lebih sederhana".
Saya pikir contoh loop non-primitif Steve Yegge menggambarkan poin saya dengan sangat baik: http://sites.google.com/site/steveyegge2/language-trickery-and-ejb
Pikirkan ini: seberapa sering Anda menggunakan tipe fungsi dalam bahasa yang memiliki sintaksis yang baik untuk mereka (seperti bahasa fungsional, python, ruby, dan bahkan C) dibandingkan dengan java di mana Anda harus mensimulasikan mereka menggunakan antarmuka seperti Runnable dan Callable dan kelas tanpa nama.
sumber
Beberapa alasan untuk tidak menyingkirkan primitif:
Jika dihilangkan, program lama apa pun tidak akan berjalan
Seluruh JVM harus ditulis ulang untuk mendukung hal baru ini.
Anda harus menyimpan nilai dan referensi, yang menggunakan lebih banyak memori. Jika Anda memiliki array byte yang sangat besar, menggunakan
byte
's secara signifikan lebih kecil daripada menggunakanByte
' s.Mendeklarasikan
int i
kemudian melakukan hal-hal dengan tidaki
akan menghasilkan masalah, tetapi menyatakanInteger i
dan kemudian melakukan hal yang sama akan menghasilkan NPE.Pertimbangkan kode ini:
Akan salah. Operator harus kelebihan beban, dan itu akan menghasilkan penulisan ulang yang utama.
Pembungkus objek secara signifikan lebih lambat daripada rekan-rekan primitif mereka.
sumber
Objek jauh lebih berat daripada tipe primitif, jadi tipe primitif jauh lebih efisien daripada instance kelas pembungkus.
Tipe-tipe primitif sangat sederhana: misalnya int adalah 32 bit dan membutuhkan 32 bit dalam memori, dan dapat dimanipulasi secara langsung. Objek Integer adalah objek lengkap, yang (seperti objek apa pun) harus disimpan di heap, dan hanya dapat diakses melalui referensi (pointer) ke sana. Kemungkinan besar juga membutuhkan lebih dari 32 bit (4 byte) memori.
Yang mengatakan, fakta bahwa Jawa memiliki perbedaan antara tipe primitif dan non-primitif juga merupakan tanda usia bahasa pemrograman Java. Bahasa pemrograman yang lebih baru tidak memiliki perbedaan ini; kompiler dari bahasa seperti itu cukup pintar untuk mengetahui dengan sendirinya jika Anda menggunakan nilai-nilai sederhana atau objek yang lebih kompleks.
Misalnya, di Scala tidak ada tipe primitif; ada Int kelas untuk integer, dan Int adalah objek nyata (yang dapat Anda metode pada dll.). Ketika kompiler mengkompilasi kode Anda, ia menggunakan int primitif di belakang layar, jadi menggunakan Int sama efisiennya dengan menggunakan int primitif di Jawa.
sumber
Selain apa yang dikatakan orang lain, variabel lokal primitif tidak dialokasikan dari heap, tetapi pada stack. Tetapi benda-benda dialokasikan dari tumpukan dan dengan demikian harus dikumpulkan dari sampah.
sumber
Tipe primitif memiliki banyak keunggulan:
sumber
Sulit untuk mengetahui jenis optimasi apa yang terjadi di bawah selimut.
Untuk penggunaan lokal, ketika kompiler memiliki informasi yang cukup untuk membuat optimisasi tidak termasuk kemungkinan nilai nol, saya berharap kinerjanya sama atau serupa .
Namun, susunan primitif ternyata sangat berbeda dari koleksi primitif kotak. Ini masuk akal mengingat bahwa sangat sedikit optimasi yang mungkin dilakukan jauh di dalam koleksi.
Selain itu,
Integer
memiliki overhead logis yang jauh lebih tinggi dibandingkan denganint
: sekarang Anda harus khawatir tentang apakahint a = b + c;
melempar pengecualian atau tidak .Saya akan menggunakan primitif sebanyak mungkin dan mengandalkan metode pabrik dan autoboxing untuk memberi saya jenis kotak yang lebih kuat secara semantik ketika dibutuhkan.
sumber
Di samping catatan, saya tidak keberatan melihat sesuatu seperti ini menemukan jalannya ke Jawa.
Di mana for loop secara otomatis menambah loop1 dari 0 hingga 1000 atau
Di mana for loop secara otomatis mengurangi loop1 1000 ke 0.
sumber
Anda harus bertanya mengapa jenis Kelas / Objek diperlukan
Alasan memiliki jenis Objek adalah untuk membuat hidup kita lebih mudah ketika kita berurusan dengan Koleksi. Primitif tidak dapat ditambahkan langsung ke Daftar / Peta daripada Anda harus menulis kelas pembungkus. Readymade Integer jenis Kelas membantu Anda di sini plus ia memiliki banyak metode utilitas seperti Integer.pareseInt (str)
sumber
Saya setuju dengan jawaban sebelumnya, menggunakan benda pembungkus primitif bisa mahal. Tetapi, jika kinerja tidak kritis dalam aplikasi Anda, Anda menghindari kelebihan saat menggunakan objek. Sebagai contoh:
Nilai
bigNumber
-2147483647, dan Anda mengharapkannya menjadi 2147483649. Ini adalah bug dalam kode yang akan diperbaiki dengan melakukan:Dan
bigNumber
akan menjadi 2147483649. Bug semacam ini kadang-kadang mudah dilewatkan dan dapat menyebabkan perilaku atau kerentanan yang tidak diketahui (lihat CWE-190 ).Jika Anda menggunakan objek pembungkus, kode yang sama tidak akan dikompilasi.
Jadi lebih mudah untuk menghentikan masalah semacam ini dengan menggunakan objek pembungkus primitif.
Pertanyaan Anda sudah dijawab, sehingga saya membalas hanya untuk menambahkan sedikit informasi lebih banyak yang tidak disebutkan sebelumnya.
sumber
Karena JAVA melakukan semua operasi matematika dalam tipe primitif. Pertimbangkan contoh ini:
Di sini, pengingat dan operasi unary plus tidak dapat diterapkan pada tipe Integer (Referensi), kompiler melakukan unboxing dan melakukan operasi.
Jadi, pastikan berapa banyak operasi autoboxing dan unboxing yang terjadi di program java. Karena, butuh waktu untuk melakukan operasi ini.
Secara umum, lebih baik menyimpan argumen tipe Referensi dan hasil tipe primitif.
sumber
The tipe primitif yang jauh lebih cepat dan memerlukan banyak memori kurang . Karena itu, kami mungkin ingin lebih suka menggunakannya.
Di sisi lain, spesifikasi bahasa Java saat ini tidak memungkinkan penggunaan tipe primitif dalam tipe parameter (generik), dalam koleksi Java atau API Refleksi.
Ketika aplikasi kita membutuhkan koleksi dengan sejumlah besar elemen, kita harus mempertimbangkan untuk menggunakan array dengan tipe yang lebih ekonomis.
* Untuk info rinci, lihat sumbernya: https://www.baeldung.com/java-primitive-vs-objects
sumber
Singkatnya: tipe primitif lebih cepat dan membutuhkan lebih sedikit memori daripada yang kotak
sumber