Saat menggunakan JDK yang sama (yaitu javac
executable yang sama ), apakah file kelas yang dihasilkan selalu identik? Apakah ada perbedaan bergantung pada sistem operasi atau perangkat keras ? Kecuali versi JDK, apakah ada faktor lain yang menyebabkan perbedaan? Apakah ada opsi kompiler untuk menghindari perbedaan? Apakah perbedaan hanya mungkin dalam teori atau apakah Oracle javac
benar - benar menghasilkan file kelas yang berbeda untuk opsi input dan compiler yang sama?
Pembaruan 1 Saya tertarik pada generasi , yaitu keluaran kompiler, bukan apakah file kelas dapat dijalankan pada berbagai platform.
Perbarui 2 Dengan 'JDK yang Sama', maksud saya juga javac
dapat dieksekusi yang sama .
Perbarui 3 Perbedaan antara perbedaan teoritis dan perbedaan praktis di kompiler Oracle.
[EDIT, menambahkan pertanyaan yang diparafrasekan]
"Bagaimana keadaan di mana javac yang sama dapat dieksekusi, ketika dijalankan pada platform yang berbeda, akan menghasilkan bytecode yang berbeda?"
sumber
Jawaban:
Mari kita begini:
Saya dapat dengan mudah menghasilkan kompiler Java yang sepenuhnya sesuai yang tidak pernah menghasilkan
.class
file yang sama dua kali, mengingat.java
file yang sama .Saya dapat melakukan ini dengan mengutak-atik semua jenis konstruksi bytecode atau hanya dengan menambahkan atribut yang berlebihan ke metode saya (yang diizinkan).
Mengingat bahwa spesifikasi tidak memerlukan kompilator untuk menghasilkan file kelas identik byte-untuk-byte, saya akan menghindari bergantung pada hasil seperti itu.
Namun , beberapa kali saya memeriksa, mengkompilasi file sumber yang sama dengan kompilator yang sama dengan sakelar yang sama (dan pustaka yang sama!) Memang menghasilkan
.class
file yang sama .Pembaruan: Saya baru-baru ini tersandung pada posting blog yang menarik ini tentang penerapan
switch
onString
di Java 7 . Dalam posting blog ini, ada beberapa bagian yang relevan, yang akan saya kutip di sini (penekanan milik saya):Ini cukup jelas menggambarkan masalah: Kompilator tidak diharuskan untuk bertindak secara deterministik, selama cocok dengan spesifikasi. Pengembang kompiler, bagaimanapun, menyadari bahwa pada umumnya ide yang bagus untuk dicoba (asalkan tidak terlalu mahal, mungkin).
sumber
Tidak ada kewajiban bagi kompiler untuk menghasilkan bytecode yang sama di setiap platform. Anda harus berkonsultasi dengan
javac
utilitas vendor yang berbeda untuk mendapatkan jawaban yang spesifik.Saya akan menunjukkan contoh praktis untuk ini dengan pemesanan file.
Katakanlah kita memiliki 2 file jar:
my1.jar
danMy2.jar
. Mereka diletakkan dilib
direktori, berdampingan. Kompilator membacanya dalam urutan abjad (karena inilib
), tetapi urutannya adalahmy1.jar
,My2.jar
jika sistem file tidak peka huruf besar / kecil, danMy2.jar
,my1.jar
jika peka huruf besar / kecil.The
my1.jar
memiliki kelasA.class
dengan metodeItu
My2.jar
samaA.class
, tetapi dengan tanda tangan metode yang berbeda (menerimaObject
):Jelas bahwa jika Anda memiliki panggilan
itu akan mengkompilasi panggilan metode dengan tanda tangan berbeda dalam kasus yang berbeda. Jadi, bergantung pada sensitivitas huruf besar sistem file Anda, Anda akan mendapatkan kelas yang berbeda sebagai hasilnya.
sumber
javac
tidak sama, karena Anda memiliki binari yang berbeda di setiap platform (mis. Win7, Linux, Solaris, Mac). Untuk vendor, tidak masuk akal untuk memiliki implementasi yang berbeda, tetapi masalah spesifik platform apa pun dapat memengaruhi hasilnya (mis. Pemesanan flie dalam direktori (pikirkanlib
direktori Anda ), endianness, dll).javac
diimplementasikan di Java (danjavac
hanya launcher asli sederhana), jadi sebagian besar perbedaan platform seharusnya tidak berdampak.Jawaban Singkat - TIDAK
Jawaban panjang
Mereka
bytecode
tidak harus sama untuk platform yang berbeda. Ini adalah JRE (Java Runtime Environment) yang tahu bagaimana persisnya menjalankan bytecode.Jika Anda melihat spesifikasi Java VM, Anda akan mengetahui bahwa ini tidak harus benar bahwa bytecode sama untuk platform yang berbeda.
Melalui format file kelas , ini menunjukkan struktur file kelas sebagai
Memeriksa tentang versi minor dan mayor
Membaca lebih banyak melalui catatan kaki
Jadi, menyelidiki semua ini menunjukkan bahwa file kelas yang dihasilkan pada platform berbeda tidak harus identik.
sumber
Pertama, sama sekali tidak ada jaminan seperti itu dalam spesifikasi. Kompiler yang sesuai dapat menandai waktu kompilasi ke dalam file kelas yang dihasilkan sebagai atribut tambahan (khusus), dan file kelas tersebut akan tetap benar. Namun itu akan menghasilkan file yang berbeda tingkat byte pada setiap build, dan sepele.
Kedua, bahkan tanpa trik buruk seperti itu, tidak ada alasan untuk mengharapkan kompilator melakukan hal yang persis sama dua kali berturut-turut kecuali jika konfigurasi dan inputnya identik dalam kedua kasus tersebut. Spesifikasi tidak menggambarkan nama file sumber sebagai salah satu atribut standar, dan menambahkan baris kosong ke file sumber baik bisa mengubah tabel nomor baris.
Ketiga, saya tidak pernah menemukan perbedaan dalam build karena platform host (selain yang disebabkan oleh perbedaan dalam classpath). Kode yang akan bervariasi berdasarkan platform (yaitu, pustaka kode asli) bukan bagian dari file kelas, dan pembuatan kode asli sebenarnya dari bytecode terjadi setelah kelas dimuat.
Keempat (dan yang paling penting) itu berbau proses yang buruk bau (seperti bau kode, tapi bagaimana Anda bertindak pada kode) ingin tahu ini. Buat versi sumber jika memungkinkan, bukan build, dan jika Anda perlu membuat versi build, buat versi di tingkat seluruh komponen dan bukan pada file kelas individual. Untuk preferensi, gunakan server CI (seperti Jenkins) untuk mengelola proses mengubah sumber menjadi kode yang dapat dijalankan.
sumber
Saya yakin, jika Anda menggunakan JDK yang sama, kode byte yang dihasilkan akan selalu sama, tanpa ada hubungannya dengan harware dan OS yang digunakan. Produksi kode byte dilakukan oleh kompilator java, yang menggunakan algoritma deterministik untuk "mengubah" kode sumber menjadi kode byte. Jadi, outputnya akan selalu sama. Dalam kondisi ini, hanya pembaruan pada kode sumber yang akan memengaruhi keluaran.
sumber
Secara keseluruhan, saya harus mengatakan tidak ada jaminan bahwa sumber yang sama akan menghasilkan bytecode yang sama ketika dikompilasi oleh kompiler yang sama tetapi pada platform yang berbeda.
Saya akan melihat skenario yang melibatkan bahasa yang berbeda (halaman kode), misalnya Windows dengan dukungan bahasa Jepang. Pikirkan karakter multi-byte; kecuali kompilator selalu menganggap ia perlu mendukung semua bahasa yang mungkin dioptimalkan untuk ASCII 8-bit.
Ada bagian tentang kompatibilitas biner di Spesifikasi Bahasa Java .
sumber
Java allows you write/compile code on one platform and run on different platform.
AFAIK ; ini hanya mungkin jika file kelas yang dihasilkan pada platform yang berbeda sama atau secara teknis sama yaitu identik.Edit
Yang saya maksud dengan komentar yang secara teknis sama adalah itu. Keduanya tidak harus persis sama jika Anda membandingkan byte demi byte.
Jadi, sesuai spesifikasi file .class kelas pada platform yang berbeda tidak perlu mencocokkan byte-by-byte.
sumber
Untuk pertanyaan:
Itu Cross-Compilation menunjukkan bagaimana kita dapat menggunakan opsi Javac: -target version
Bendera ini menghasilkan file kelas yang kompatibel dengan versi Java yang kami tentukan saat menjalankan perintah ini. Oleh karena itu, file kelas akan berbeda tergantung pada atribut yang kami berikan selama kompaliasi menggunakan opsi ini.
sumber
Kemungkinan besar, jawabannya adalah "ya", tetapi untuk mendapatkan jawaban yang tepat, seseorang perlu mencari beberapa kunci atau generasi panduan selama kompilasi.
Saya tidak dapat mengingat situasi di mana ini terjadi. Misalnya memiliki ID untuk keperluan serialisasi itu adalah hardcoded, yaitu dihasilkan oleh programmer atau IDE.
PS Juga JNI bisa menjadi masalah.
PPS yang saya temukan
javac
sendiri ditulis dalam java. Artinya, ini identik pada platform yang berbeda. Karenanya itu tidak akan menghasilkan kode yang berbeda tanpa alasan. Jadi, ini hanya dapat dilakukan dengan panggilan asli.sumber
Ada dua pertanyaan.
Ini adalah pertanyaan teoretis, dan jawabannya jelas, ya, mungkin ada. Seperti yang dikatakan orang lain, spesifikasi tidak memerlukan kompilator untuk menghasilkan file kelas identik byte-untuk-byte.
Bahkan jika setiap kompiler yang ada saat ini menghasilkan kode byte yang sama dalam semua keadaan (perangkat keras yang berbeda, dll.), Jawabannya besok mungkin berbeda. Jika Anda tidak pernah berencana untuk memperbarui javac atau sistem operasi Anda, Anda dapat menguji perilaku versi tersebut dalam keadaan khusus Anda, tetapi hasilnya mungkin berbeda jika Anda beralih dari, misalnya, Java 7 Update 11 ke Java 7 Update 15.
Itu tidak bisa diketahui.
Saya tidak tahu apakah manajemen konfigurasi adalah alasan Anda mengajukan pertanyaan, tetapi ini alasan yang dapat dimengerti untuk peduli. Membandingkan kode byte adalah kontrol TI yang sah, tetapi hanya untuk menentukan apakah file kelas berubah, bukan menentukan apakah file sumber berubah.
sumber
Saya akan mengatakannya dengan cara lain.
Pertama, saya pikir pertanyaannya bukan tentang deterministik:
Tentu saja ini deterministik: keacakan sulit dicapai dalam ilmu komputer, dan tidak ada alasan penyusun akan memperkenalkannya di sini untuk alasan apa pun.
Kedua, jika Anda memformulasi ulang dengan "seberapa mirip file bytecode untuk file kode sumber yang sama?", Maka Tidak , Anda tidak dapat mengandalkan fakta bahwa keduanya akan serupa .
Cara yang baik untuk memastikan ini, adalah dengan membiarkan .class (atau .pyc dalam kasus saya) di tahap git Anda. Anda akan menyadari bahwa di antara komputer yang berbeda dalam tim Anda, pemberitahuan git berubah di antara file .pyc, ketika tidak ada perubahan yang dibawa ke file .py (dan .pyc tetap dikompilasi ulang).
Setidaknya itulah yang saya amati. Jadi letakkan * .pyc dan * .class di .gitignore Anda!
sumber