Mengapa Java API menggunakan int
, ketika short
atau bahkan byte
sudah cukup?
Contoh: DAY_OF_WEEK
Bidang di kelas Calendar
digunakan int
.
Jika perbedaannya terlalu minimal, lalu mengapa tipe data ( short
, int
) itu ada?
Mengapa Java API menggunakan int
, ketika short
atau bahkan byte
sudah cukup?
Contoh: DAY_OF_WEEK
Bidang di kelas Calendar
digunakan int
.
Jika perbedaannya terlalu minimal, lalu mengapa tipe data ( short
, int
) itu ada?
Jawaban:
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 int
dan tipenya long
, dan bukan untuk tipe yang lebih kecil.
(Selain: Jenis yang lebih kecil ( byte
dan 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 long
nilai 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_WEEK
sebagai 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", double
dan long
, menempati dua slot). Jadi secara eksplisit mendeklarasikan bidang sebagai short
atau byte
tidak akan menyimpan memori apa pun.
int
. Jika Anda memiliki referensi ke implementasi lain, saya akan memperbarui jawabannya dan memasukkan tautan yang sesuai.
(Hampir) Semua operasi di byte
, short
akan 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. byte
dan short
akan memperumit masalah, menurut saya pengoptimalan mikro ini tidak sepadan karena kita berbicara tentang jumlah variabel yang tetap.
byte
relevan 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 Calendar
kelas 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
, short
dan primitif lainnya tidak akan membuat perbedaan sama sekali. Selain itu, banyak implementasi Java menyelaraskan variabel * (dan objek).
* byte
dan short
menempati ruang yang sama seolah- int
olah 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, byte
ambil 1 byte, short
ambil 2 byte dan int
ambil 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.
short
.
Karena operasi aritmatika lebih mudah jika menggunakan bilangan bulat dibandingkan dengan short. Asumsikan bahwa konstanta memang dimodelkan oleh short
nilai. 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 int
nilai ketika digunakan dalam operasi aritmatika. (Pada tumpukan operan, celana pendek bahkan diekspresikan sebagai int.) Ini akan sangat rumit untuk digunakan, itulah sebabnya int
nilai 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 int
menjadi short
akan mengamankan Anda 40 * 16 bit = 80 byte
. Lihat jawaban ini untuk referensi lebih lanjut.
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.
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 float
presisi, tetapi terkadang akan menghasilkan nilai yang sedikit kurang akurat. Bagaimanapun, Sun memutuskan semuanya harus dilakukan dengan cara yang sama, dan mereka memilih untuk menggunakan float
nilai 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 byte
baik daripada long
menyimpan tujuh byte; memiliki larik 1.000.000 bilangan yang menahan setiap bilangan sebagai byte
bukan along
gelombang 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.
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 Calendar
metode terkait mengembalikan file byte
. Tetapi tidak ada Calendar
metode seperti itu , hanya get(int)
yang harus mengembalikan int
karena 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 int
atau menulis setter seperti
void setDayOfWeek(int dayOfWeek) {
this.dayOfWeek = checkedCastToByte(dayOfWeek);
}
Maka jenisnya DAY_OF_WEEK
tidak masalah.