Mengapa Java API menggunakan int, bukan pendek atau byte?


Jawaban:


168

Beberapa alasan telah dikemukakan. Misalnya, fakta bahwa "... (Hampir) Semua operasi pada byte, pendek akan mempromosikan primitif ini ke int" . Namun, pertanyaan selanjutnya yang jelas adalah: MENGAPA tipe ini dipromosikan int?

Jadi untuk melangkah lebih dalam: Jawabannya mungkin hanya terkait dengan Set Instruksi Mesin Virtual Java. Seperti yang dirangkum dalam Tabel di Spesifikasi Mesin Virtual Java , semua operasi aritmatika integral, seperti menambah, membagi, dan lainnya, hanya tersedia untuk tipe intdan tipenya long, dan bukan untuk tipe yang lebih kecil.

(Selain: Jenis yang lebih kecil ( bytedan short) pada dasarnya hanya ditujukan untuk array . Sebuah array seperti new byte[1000]akan membutuhkan 1000 byte, dan array seperti new int[1000]akan membutuhkan 4000 byte)

Sekarang, tentu saja, orang dapat mengatakan bahwa "... pertanyaan selanjutnya yang jelas adalah: MENGAPA instruksi ini hanya ditawarkan untuk int(dan long)?" .

Salah satu alasannya disebutkan dalam Spesifikasi JVM yang disebutkan di atas:

Jika setiap instruksi yang diketik mendukung semua tipe data run-time Mesin Virtual Java, akan ada lebih banyak instruksi daripada yang dapat direpresentasikan dalam satu byte

Selain itu, Mesin Virtual Java dapat dianggap sebagai abstraksi dari prosesor yang sebenarnya. Dan memperkenalkan Unit Logika Aritmatika khusus untuk jenis yang lebih kecil tidak akan sepadan dengan usaha: Ini akan membutuhkan transistor tambahan, tetapi masih hanya dapat mengeksekusi satu penambahan dalam satu siklus jam. Arsitektur dominan ketika JVM dirancang adalah 32bits, tepat untuk 32bit int. (Operasi yang melibatkan longnilai 64bit diimplementasikan sebagai kasus khusus).

(Catatan: Paragraf terakhir agak terlalu disederhanakan, mempertimbangkan kemungkinan vektorisasi, dll., Tetapi harus memberikan ide dasar tanpa menyelam terlalu dalam ke topik desain prosesor)


EDIT: Tambahan singkat, berfokus pada contoh dari pertanyaan, tetapi dalam pengertian yang lebih umum: Seseorang juga dapat bertanya apakah tidak bermanfaat untuk menyimpan bidang menggunakan tipe yang lebih kecil. Misalnya, orang mungkin berpikir bahwa memori dapat disimpan dengan menyimpan Calendar.DAY_OF_WEEKsebagai file byte. Tapi di sini, Format File Kelas Java ikut bermain: Semua Kolom dalam File Kelas menempati setidaknya satu "slot", yang memiliki ukuran satu int(32 bit). (Kolom "lebar", doubledan long, menempati dua slot). Jadi secara eksplisit mendeklarasikan bidang sebagai shortatau bytetidak akan menyimpan memori apa pun.


Saya akan menebak bahwa logika mengapa operand dipromosikan menjadi int juga terkait dengan alasan yang digunakan dalam C dan C ++
Shafik Yaghmour

@ Marco13 "Jadi secara eksplisit mendeklarasikan bidang sebagai pendek atau byte juga tidak akan menghemat memori." Benarkah itu? Saya tidak berpikir itu benar.
ACV

@ACV Sebenarnya, implementasi dapat memilih untuk menyimpan bentuk yang lebih ringkas, tetapi format yang diekspos "secara virtual" (yaitu oleh mesin virtual) akan memperlakukan nilai setidaknya memiliki ukuran int. Jika Anda memiliki referensi ke implementasi lain, saya akan memperbarui jawabannya dan memasukkan tautan yang sesuai.
Marco13

41

(Hampir) Semua operasi di byte, shortakan mempromosikannya ke int, misalnya, Anda tidak dapat menulis:

short x = 1;
short y = 2;

short z = x + y; //error

Aritmatika lebih mudah dan langsung saat digunakan int, tidak perlu dicetak.

Dalam hal ruang, itu membuat sangat sedikit perbedaan. bytedan shortakan memperumit masalah, menurut saya pengoptimalan mikro ini tidak sepadan karena kita berbicara tentang jumlah variabel yang tetap.

byterelevan dan berguna saat Anda memprogram untuk perangkat yang disematkan atau berurusan dengan file / jaringan. Juga primitif ini terbatas, bagaimana jika perhitungannya mungkin melebihi batas mereka di masa depan? Coba pikirkan tentang perpanjangan Calendarkelas yang mungkin mengembangkan jumlah yang lebih besar.

Perhatikan juga bahwa dalam prosesor 64-bit, penduduk lokal akan disimpan dalam register dan tidak akan menggunakan sumber daya apa pun, jadi menggunakan int, shortdan primitif lainnya tidak akan membuat perbedaan sama sekali. Selain itu, banyak implementasi Java menyelaraskan variabel * (dan objek).


* byte dan shortmenempati ruang yang sama seolah- intolah itu adalah variabel lokal , variabel kelas , atau bahkan variabel instan . Mengapa? Karena di (kebanyakan) sistem komputer, alamat variabel disejajarkan , jadi misalnya jika Anda menggunakan satu byte, Anda sebenarnya akan mendapatkan dua byte - satu untuk variabel itu sendiri dan satu lagi untuk padding.

Di sisi lain, dalam array, byteambil 1 byte, shortambil 2 byte dan intambil empat byte, karena dalam array hanya awal dan mungkin akhir yang harus disejajarkan. Ini akan membuat perbedaan jika Anda ingin menggunakan, misalnya System.arraycopy(), maka Anda akan benar-benar mencatat perbedaan kinerja.


1
Fakta menarik: Jika Anda menggunakan pengubah akhir untuk kedua nilai, ini akan berhasil. :)
Alexander

@alexander kenapa?
pilih

2
@elect Dalam hal ini, kompilator dapat yakin bahwa jumlahnya valid short.
Maroun

7

Karena operasi aritmatika lebih mudah jika menggunakan bilangan bulat dibandingkan dengan short. Asumsikan bahwa konstanta memang dimodelkan oleh shortnilai. Maka Anda harus menggunakan API dengan cara ini:

short month = Calendar.JUNE;
month = month + (short) 1; // is july

Perhatikan casting eksplisitnya. Nilai pendek secara implisit dipromosikan menjadi intnilai ketika digunakan dalam operasi aritmatika. (Pada tumpukan operan, celana pendek bahkan diekspresikan sebagai int.) Ini akan sangat rumit untuk digunakan, itulah sebabnya intnilai sering disukai untuk konstanta.

Dibandingkan dengan itu, keuntungan dalam efisiensi penyimpanan minimal karena hanya ada sejumlah konstanta yang tetap. Kita berbicara tentang 40 konstanta. Mengubah penyimpanannya dari intmenjadi shortakan mengamankan Anda 40 * 16 bit = 80 byte. Lihat jawaban ini untuk referensi lebih lanjut.


5

Jika Anda menggunakan filosofi di mana konstanta integral disimpan dalam tipe terkecil yang mereka cocokkan, maka Java akan memiliki masalah serius: setiap kali pemrogram menulis kode menggunakan konstanta integral, mereka harus memperhatikan kodenya dengan cermat untuk memeriksa apakah tipe dari konstanta penting, dan jika demikian cari jenisnya dalam dokumentasi dan / atau lakukan konversi jenis apa pun yang diperlukan.

Jadi sekarang setelah kami menguraikan masalah serius, manfaat apa yang dapat Anda harapkan dengan filosofi itu? Saya tidak akan terkejut jika satu - satunya efek yang dapat diamati runtime dari perubahan itu akan menjadi jenis apa yang Anda dapatkan ketika Anda melihat konstanta melalui refleksi. (dan, tentu saja, kesalahan apa pun yang diperkenalkan oleh pemrogram yang malas / tidak sadar tidak memperhitungkan jenis konstanta dengan benar)

Menimbang pro dan kontra sangat mudah: ini adalah filosofi yang buruk.


4

Kompleksitas desain mesin virtual adalah fungsi dari berapa banyak jenis operasi yang dapat dilakukannya. Lebih mudah untuk memiliki empat implementasi dari instruksi seperti "multiply" - masing-masing satu untuk integer 32-bit, integer 64-bit, floating-point 32-bit, dan floating-point 64-bit - daripada memiliki, sebagai tambahan di atas, versi untuk tipe numerik yang lebih kecil juga. Pertanyaan desain yang lebih menarik adalah mengapa harus ada empat jenis, bukan lebih sedikit (melakukan semua komputasi bilangan bulat dengan bilangan bulat 64-bit dan / atau melakukan semua komputasi titik-mengambang dengan nilai titik-mengambang 64-bit). Alasan untuk menggunakan integer 32-bit adalah karena Java diharapkan dapat berjalan pada banyak platform di mana tipe 32-bit dapat dijalankan secepat tipe 16-bit atau 8-bit, tetapi operasi pada tipe 64-bit akan terasa lebih lambat.hanya memiliki tipe 32-bit.

Sedangkan untuk melakukan perhitungan floating-point pada nilai 32-bit, keuntungannya sedikit kurang jelas. Ada beberapa platform di mana komputasi sukafloat a=b+c+d;dapat dilakukan paling cepat dengan mengonversi semua operan ke tipe presisi lebih tinggi, menambahkannya, lalu mengonversi hasilnya kembali ke angka floating-point 32-bit untuk penyimpanan. Ada platform lain yang akan lebih efisien untuk melakukan semua komputasi menggunakan nilai floating-point 32-bit. Pembuat Java memutuskan bahwa semua platform harus diharuskan melakukan hal-hal dengan cara yang sama, dan bahwa mereka harus menyukai platform perangkat keras yang komputasi floating-point 32-bitnya lebih cepat daripada yang lebih lama, meskipun PC ini sangat menurunkan kecepatan keduanya. dan presisi matematika floating-point pada PC biasa, serta pada banyak mesin tanpa unit floating-point. Perhatikan, btw, bahwa bergantung pada nilai b, c, dan d, menggunakan komputasi perantara presisi tinggi saat menghitung ekspresi seperti yang disebutkan di atasfloat a=b+c+d;terkadang akan menghasilkan hasil yang secara signifikan lebih akurat daripada yang akan dicapai dari semua operan perantara yang dihitung dengan floatpresisi, tetapi terkadang akan menghasilkan nilai yang sedikit kurang akurat. Bagaimanapun, Sun memutuskan semuanya harus dilakukan dengan cara yang sama, dan mereka memilih untuk menggunakan floatnilai presisi minimal .

Perhatikan bahwa keuntungan utama dari tipe data yang lebih kecil menjadi jelas ketika sejumlah besar dari mereka disimpan bersama dalam sebuah larik; bahkan jika tidak ada keuntungan memiliki variabel individu dengan tipe yang lebih kecil dari 64-bit, ada baiknya memiliki array yang dapat menyimpan nilai yang lebih kecil dengan lebih kompak; memiliki variabel lokal lebih bytebaik daripada longmenyimpan tujuh byte; memiliki larik 1.000.000 bilangan yang menahan setiap bilangan sebagai bytebukan alonggelombang 7.000.000 byte. Karena setiap jenis array hanya perlu mendukung beberapa operasi (terutama membaca satu item, menyimpan satu item, menyalin berbagai item dalam array, atau menyalin berbagai item dari satu array ke yang lain), kompleksitas yang ditambahkan memiliki lebih banyak tipe array tidak separah kerumitan karena memiliki lebih banyak tipe nilai numerik diskrit yang dapat langsung digunakan.


2

Sebenarnya, hanya ada sedikit keuntungan. Jika Anda memiliki file

class MyTimeAndDayOfWeek {
    byte dayOfWeek;
    byte hour;
    byte minute;
    byte second;
}

kemudian pada JVM tipikal itu membutuhkan ruang sebanyak kelas yang berisi satu int. Konsumsi memori dibulatkan ke kelipatan 8 atau 16 byte berikutnya (IIRC, yang dapat dikonfigurasi), jadi kasus ketika ada penyimpanan sebenarnya agak jarang.

Kelas ini akan sedikit lebih mudah digunakan jika Calendarmetode terkait mengembalikan file byte. Tetapi tidak ada Calendarmetode seperti itu , hanya get(int)yang harus mengembalikan intkarena bidang lain. Setiap operasi pada jenis yang lebih kecil dipromosikan ke int, jadi Anda membutuhkan banyak transmisi.

Kemungkinan besar, Anda akan menyerah dan beralih ke intatau menulis setter seperti

void setDayOfWeek(int dayOfWeek) {
    this.dayOfWeek = checkedCastToByte(dayOfWeek);
}

Maka jenisnya DAY_OF_WEEKtidak masalah.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.