Di Jawa ada tipe primitif untuk byte
, short
, int
dan long
dan hal yang sama untuk float
dan double
. Mengapa orang harus menetapkan berapa byte yang harus digunakan untuk nilai primitif? Tidak bisakah ukurannya ditentukan secara dinamis tergantung pada seberapa besar angka yang dilewati?
Ada 2 alasan yang dapat saya pikirkan:
- Mengatur ukuran data secara dinamis berarti perlu mengubah secara dinamis juga. Ini berpotensi menyebabkan masalah kinerja?
- Mungkin programmer tidak ingin seseorang dapat menggunakan angka yang lebih besar dari ukuran tertentu dan ini memungkinkan mereka untuk membatasinya.
Saya masih berpikir ada banyak hal yang bisa didapat dengan menggunakan satu int
dan float
tipe, apakah ada alasan khusus Java memutuskan untuk tidak menggunakan rute ini?
java
language-design
data-types
numbers
Yitzih
sumber
sumber
Jawaban:
Seperti banyak aspek dari desain bahasa, ia datang ke trade-off keanggunan terhadap kinerja (belum lagi beberapa pengaruh historis dari bahasa sebelumnya).
Alternatif
Sangat mungkin (dan cukup sederhana) untuk membuat bahasa pemrograman yang hanya memiliki satu jenis bilangan asli
nat
. Hampir semua bahasa pemrograman yang digunakan untuk studi akademis (misalnya PCF, Sistem F) memiliki tipe angka tunggal ini, yang merupakan solusi yang lebih elegan, seperti yang Anda duga. Tetapi desain bahasa dalam praktik bukan hanya tentang keanggunan; kita juga harus mempertimbangkan kinerja (sejauh mana kinerja dianggap tergantung pada aplikasi bahasa yang dimaksudkan). Kinerja terdiri dari kendala waktu dan ruang.Kendala ruang
Membiarkan pemrogram memilih jumlah byte di muka dapat menghemat ruang dalam program yang dibatasi memori. Jika semua nomor Anda akan menjadi kurang dari 256, maka Anda dapat menggunakan 8 kali lebih banyak
byte
sebagailong
s, atau digunakan penyimpanan disimpan untuk objek yang lebih kompleks. Pengembang aplikasi Java standar tidak perlu khawatir tentang kendala ini, tetapi mereka muncul.Efisiensi
Sekalipun kita mengabaikan ruang, kita masih terkendala oleh CPU, yang hanya memiliki instruksi yang beroperasi pada jumlah byte yang tetap (8 byte pada arsitektur 64-bit). Itu berarti bahkan menyediakan tipe 8-byte tunggal
long
akan membuat implementasi bahasa secara signifikan lebih sederhana daripada memiliki tipe bilangan alami yang tidak terikat, dengan dapat memetakan operasi aritmatika secara langsung ke instruksi CPU tunggal yang mendasarinya. Jika Anda mengizinkan pemrogram untuk menggunakan angka yang besar dan sewenang-wenang, maka operasi aritmatika tunggal harus dipetakan ke urutan instruksi mesin yang rumit, yang akan memperlambat program. Ini adalah poin (1) yang Anda ajukan.Jenis titik mengambang
Diskusi sejauh ini hanya menyangkut bilangan bulat. Jenis titik-mengambang adalah binatang yang kompleks, dengan semantik yang sangat halus dan kasing tepi. Dengan demikian, meskipun kita bisa dengan mudah mengganti
int
,long
,short
, danbyte
dengan satunat
jenis, tidak jelas apa jenis floating-point bahkan adalah . Mereka bukan bilangan real, karena bilangan real tidak bisa ada dalam bahasa pemrograman. Mereka juga bukan angka yang cukup rasional (meskipun itu lurus ke depan untuk membuat tipe rasional jika diinginkan). Pada dasarnya, IEEE memutuskan cara untuk mengurutkan kira-kira bilangan real, dan semua bahasa (dan programmer) telah terjebak dengan mereka sejak itu.Akhirnya:
Ini bukan alasan yang valid. Pertama, saya tidak bisa memikirkan situasi di mana jenis secara alami dapat mengkodekan batas numerik, belum lagi kemungkinannya sangat rendah sehingga batas yang ingin ditegakkan oleh programmer akan sesuai dengan ukuran dari salah satu tipe primitif.
sumber
type my_type = int (7, 2343)
?Alasannya sangat sederhana: efisiensi . Dalam banyak cara.
Tipe data asli: Semakin dekat tipe data dari suatu bahasa sesuai dengan tipe data yang mendasari perangkat keras, semakin efisien bahasa dianggap. (Tidak dalam arti bahwa program Anda tentu akan efisien, tetapi dalam arti bahwa Anda dapat, jika Anda benar-benar tahu apa yang Anda lakukan, tulis kode yang akan berjalan seefisien perangkat keras dapat menjalankannya.) Jenis data yang ditawarkan oleh Java sesuai dengan byte, kata-kata, doubleword dan quadword dari perangkat keras paling populer di luar sana. Itu cara yang paling efisien untuk dilakukan.
Overhead yang tidak beralasan pada sistem 32-bit: Jika keputusan telah dibuat untuk memetakan semuanya ke ukuran tetap 64-bit, ini akan memberlakukan penalti besar pada arsitektur 32-bit yang membutuhkan siklus clock lebih banyak untuk melakukan 64- operasi bit daripada operasi 32-bit.
Memori yang boros: Ada banyak perangkat keras di luar sana yang tidak terlalu pilih-pilih tentang penyelarasan memori, (arsitektur Intel x86 dan x64 menjadi contohnya), jadi array 100 byte pada perangkat keras itu hanya dapat menempati 100 byte memori. Namun, jika Anda tidak memiliki byte lagi, dan Anda harus menggunakan panjang sebagai gantinya, array yang sama akan menempati urutan besarnya lebih banyak memori. Dan byte array sangat umum.
Menghitung ukuran angka: Gagasan Anda menentukan ukuran bilangan bulat secara dinamis tergantung pada seberapa besar angka yang dilewati terlalu sederhana; tidak ada satu titik "melintas" suatu angka; perhitungan seberapa besar angka yang harus dilakukan pada saat runtime, pada setiap operasi yang mungkin memerlukan hasil dari ukuran yang lebih besar: setiap kali Anda menambah angka, setiap kali Anda menambahkan dua angka, setiap kali Anda mengalikan dua angka, dll.
Operasi pada jumlah ukuran yang berbeda: Selanjutnya, memiliki jumlah ukuran yang berpotensi berbeda mengambang di memori akan menyulitkan semua operasi: Bahkan untuk sekadar membandingkan dua angka, runtime pertama-tama harus memeriksa apakah kedua angka yang akan dibandingkan adalah sama. ukuran, dan jika tidak, ubah ukuran yang lebih kecil agar sesuai dengan ukuran yang lebih besar.
Operasi yang membutuhkan ukuran operan tertentu : Operasi bit-wise tertentu bergantung pada bilangan bulat yang memiliki ukuran tertentu. Karena tidak memiliki ukuran spesifik yang telah ditentukan sebelumnya, operasi ini harus ditiru.
Overhead polimorfisme: Mengubah ukuran angka pada saat runtime pada dasarnya berarti bahwa angka tersebut harus polimorfik. Ini pada gilirannya berarti bahwa itu tidak bisa menjadi primitif ukuran tetap yang dialokasikan pada tumpukan, itu harus menjadi objek, dialokasikan pada tumpukan. Itu sangat tidak efisien. (Baca ulang # 1 di atas.)
sumber
Untuk menghindari pengulangan poin yang telah dibahas dalam jawaban lain, saya akan mencoba menguraikan berbagai perspektif.
Dari perspektif desain bahasa
Alasan historis
Ini sudah dibahas dalam artikel Wikipedia tentang sejarah Jawa, dan juga dibahas secara singkat dalam jawaban Marco13 .
Saya akan menunjukkan bahwa:
Alasan efisiensi
Kapan efisiensi?
Efisiensi penyimpanan (dalam memori, atau pada disk)
Efisiensi eksekusi (dalam CPU, atau antara CPU dan memori)
Kebutuhan akan bahasa pemrograman untuk menyediakan abstraksi untuk bilangan bulat kecil, meskipun terbatas pada konteks tertentu
Interoperabilitas
char
array ukuran 256. (Contoh.)BitConverter
) untuk membantu pengemasan dan pembongkaran bilangan bulat sempit menjadi bit-stream dan byte-stream.Penanganan string
Penanganan format file
Keinginan, kualitas perangkat lunak, dan tanggung jawab programmer
Pertimbangkan skenario berikut.
Seringkali, perangkat lunak yang dapat dengan aman meningkatkan banyak pesanan besarnya harus direkayasa untuk tujuan itu, dengan meningkatnya kompleksitas. Itu tidak datang secara otomatis bahkan jika masalah integer overflow dihilangkan. Ini datang ke lingkaran penuh menjawab perspektif desain bahasa: sering kali, perangkat lunak yang menolak untuk melakukan pekerjaan ketika overflow bilangan bulat yang tidak diinginkan terjadi (dengan melemparkan kesalahan atau pengecualian) lebih baik daripada perangkat lunak yang secara otomatis sesuai dengan operasi besar astronomi.
Ini berarti perspektif OP,
tidak benar. Programmer harus diizinkan, dan kadang-kadang diperlukan, untuk menentukan besarnya maksimum yang dapat diambil nilai integer, pada bagian-bagian penting dari perangkat lunak. Seperti yang ditunjukkan oleh jawaban gardenhead , batas alami yang dikenakan oleh tipe primitif tidak berguna untuk tujuan ini; bahasa harus menyediakan cara bagi programmer untuk menyatakan besaran dan menegakkan batasan tersebut.
sumber
Itu semua berasal dari perangkat keras.
Byte adalah unit memori terkecil yang dapat dialamatkan pada sebagian besar perangkat keras.
Setiap jenis yang Anda sebutkan dibangun dari beberapa byte.
Satu byte adalah 8 bit. Dengan itu Anda bisa mengekspresikan 8 boolean tetapi Anda tidak bisa melihat satu per satu. Anda mengalamatkan 1, Anda mengalamatkan semua 8.
Dulu sesederhana itu tetapi kemudian kami beralih dari bus 8 bit ke bus 16, 32, dan sekarang 64 bit.
Yang berarti sementara kita masih bisa mengatasi pada tingkat byte kita tidak dapat mengambil lagi satu byte dari memori tanpa mendapatkan byte tetangganya.
Menghadapi perangkat keras ini, perancang bahasa memilih untuk mengizinkan kami memilih jenis yang memungkinkan kami memilih jenis yang sesuai dengan perangkat keras.
Anda dapat mengklaim bahwa perincian seperti itu dapat dan harus disarikan terutama dalam bahasa yang bertujuan untuk berjalan pada perangkat keras apa pun. Ini akan memiliki masalah kinerja yang disembunyikan tetapi Anda mungkin benar. Itu tidak terjadi begitu saja.
Java sebenarnya mencoba melakukan ini. Bytes secara otomatis dipromosikan menjadi Ints. Sebuah fakta yang akan membuat Anda gila ketika pertama kali Anda mencoba melakukan pekerjaan menggeser sedikit serius di dalamnya.
Jadi mengapa itu tidak berhasil?
Titik penjualan besar Java pada zaman dulu dimana Anda bisa duduk dengan algoritma C yang baik dan dikenal baik, mengetiknya di Jawa, dan dengan sedikit perubahan akan berhasil. Dan C sangat dekat dengan perangkat keras.
Menjaga agar ukuran yang berjalan dan abstrak keluar dari tipe integral tidak bekerja bersama-sama.
Jadi mereka bisa melakukannya. Mereka tidak melakukannya.
Ini pemikiran yang valid. Ada metode untuk melakukan ini. Fungsi penjepit untuk satu. Suatu bahasa bisa sejauh memanggang batas acak ke dalam jenis mereka. Dan ketika batas-batas itu diketahui pada waktu kompilasi yang akan memungkinkan optimasi dalam bagaimana angka-angka itu disimpan.
Java bukan bahasa itu.
sumber
Kemungkinan, satu alasan penting mengapa jenis-jenis ini ada di Jawa adalah sederhana dan sangat tidak teknis:
C dan C ++ juga memiliki tipe-tipe ini!
Meskipun sulit untuk memberikan bukti bahwa ini adalah alasannya, setidaknya ada beberapa bukti kuat: Spesifikasi Bahasa Oak (Versi 0.2) berisi bagian berikut:
Jadi pertanyaannya bisa menjadi:
Mengapa pendek, int, dan lama ditemukan di C?
Saya tidak yakin apakah jawaban pertanyaan surat memuaskan dalam konteks pertanyaan yang diajukan di sini. Tetapi dalam kombinasi dengan jawaban lain di sini, mungkin menjadi jelas bahwa dapat bermanfaat untuk memiliki tipe-tipe ini (terlepas dari apakah keberadaan mereka di Jawa hanya merupakan warisan dari C / C ++).
Alasan paling penting yang bisa saya pikirkan adalah
Byte adalah unit memori terkecil yang dapat dialamatkan (seperti yang sudah disebutkan oleh CandiedOrange). A
byte
adalah blok bangunan data dasar, yang dapat dibaca dari file atau melalui jaringan. Beberapa representasi eksplisit dari ini harus ada (dan itu memang ada di sebagian besar bahasa, bahkan ketika kadang-kadang datang dalam penyamaran).Memang benar bahwa, dalam praktiknya, masuk akal untuk mewakili semua bidang dan variabel lokal menggunakan tipe tunggal, dan memanggil tipe ini
int
. Ada pertanyaan terkait tentang hal itu di stackoverflow: Mengapa Java API menggunakan int, bukan pendek atau byte? . Seperti yang saya sebutkan dalam jawaban saya di sana, satu pembenaran untuk memiliki tipe yang lebih kecil (byte
danshort
) adalah bahwa Anda dapat membuat array tipe ini: Java memiliki representasi array yang masih agak "dekat dengan perangkat keras". Berbeda dengan bahasa lain (dan berbeda dengan array objek, sepertiInteger[n]
array),int[n]
array bukan kumpulan referensi di mana nilai tersebar di seluruh tumpukan. Sebaliknya, itu akan terjadidalam praktiknya menjadi blokn*4
byte berturut-turut - satu keping memori dengan ukuran dan tata letak data yang diketahui. Ketika Anda memiliki pilihan untuk menyimpan 1000 byte dalam koleksi objek nilai integer berukuran sewenang-wenang, atau dalambyte[1000]
(yang membutuhkan 1000 byte), yang terakhir mungkin memang menghemat sebagian memori. (Beberapa keuntungan lain dari ini mungkin lebih halus, dan hanya menjadi jelas ketika menghubungkan Java dengan perpustakaan asli)Mengenai hal-hal yang Anda tanyakan secara spesifik:
Mungkin akan mungkin untuk secara dinamis mengatur ukuran variabel, jika seseorang dianggap merancang bahasa pemrograman yang sama sekali baru dari awal. Saya bukan ahli dalam pembuatan kompiler, tetapi berpikir bahwa akan sulit untuk mengumpulkan koleksi yang berubah-ubah secara dinamis - terutama, ketika Anda memiliki bahasa yang sangat diketik. Jadi mungkin akan bermuara pada semua angka yang disimpan dalam "tipe data angka presisi umum yang arbitrer", yang tentunya akan memiliki dampak kinerja. Tentu saja, ada yang bahasa pemrograman yang sangat diketik dan / atau menawarkan jenis nomor berukuran sewenang-wenang, tapi saya tidak berpikir bahwa ada bahasa pemrograman tujuan umum nyata yang pergi dengan cara ini.
Catatan samping:
Anda mungkin bertanya-tanya tentang
unsigned
pengubah yang disebutkan dalam spesifikasi Oak. Bahkan, itu juga berisi komentar: "unsigned
belum diimplementasikan; mungkin tidak akan pernah." . Dan mereka benar.Selain bertanya-tanya mengapa C / C ++ memiliki tipe integer yang berbeda ini, Anda mungkin bertanya-tanya mengapa mereka mengacaukannya begitu mengerikan sehingga Anda tidak pernah tahu berapa banyak bit yang
int
dimiliki. Pembenaran untuk ini biasanya terkait dengan kinerja, dan dapat dilihat di tempat lain.sumber
Ini tentu saja menunjukkan Anda belum mengajarkan tentang kinerja dan arsitektur.
Mengabaikan pentingnya ukuran data selalu mengenai kinerja, Anda harus menggunakan sumber daya sebanyak yang diperlukan, tetapi tidak lebih, selalu!
Itulah perbedaan antara program atau sistem yang melakukan hal-hal yang sangat sederhana dan sangat tidak efisien yang membutuhkan banyak sumber daya dan membuat penggunaan sistem itu benar-benar mahal; atau sistem yang tidak banyak, tetapi berjalan lebih cepat dari yang lain dan sangat murah untuk dijalankan.
sumber
Ada beberapa alasan bagus
(1) sementara penyimpanan satu byte variabel ayat satu panjang tidak signifikan, penyimpanan jutaan dalam array sangat signifikan.
(2) aritmatika "perangkat keras asli" berdasarkan ukuran integer tertentu mungkin jauh lebih efisien, dan untuk beberapa algoritma pada beberapa platform, itu mungkin penting.
sumber