Kode berikut menghasilkan output "Hello World!" (tidak juga, coba).
public static void main(String... args) {
// The comment below is not a typo.
// \u000d System.out.println("Hello World!");
}
Alasan untuk ini adalah bahwa kompiler Java mem-parsing karakter Unicode \u000d
sebagai baris baru dan ditransformasikan menjadi:
public static void main(String... args) {
// The comment below is not a typo.
//
System.out.println("Hello World!");
}
Sehingga menghasilkan komentar yang "dieksekusi".
Karena ini dapat digunakan untuk "menyembunyikan" kode berbahaya atau apa pun yang bisa dipahami oleh seorang programmer jahat, mengapa diizinkan dalam komentar ?
Mengapa ini diizinkan oleh spesifikasi Java?
Jawaban:
Dekode Unicode dilakukan sebelum terjemahan leksikal lainnya. Manfaat utama dari ini adalah membuatnya sepele untuk bolak-balik antara ASCII dan pengkodean lainnya. Anda bahkan tidak perlu mencari tahu di mana komentar mulai dan berakhir!
Sebagaimana dinyatakan dalam JLS Bagian 3.3 ini memungkinkan alat berbasis ASCII untuk memproses file sumber:
Ini memberikan jaminan mendasar untuk independensi platform (independensi set karakter yang didukung) yang selalu menjadi tujuan utama untuk platform Java.
Mampu menulis karakter Unicode di mana saja dalam file adalah fitur yang rapi, dan terutama penting dalam komentar, ketika mendokumentasikan kode dalam bahasa non-latin. Fakta bahwa ia dapat mengganggu semantik dengan cara-cara halus seperti itu hanyalah efek samping (yang tidak menguntungkan).
Ada banyak gotcha pada tema ini dan Java Puzzlers oleh Joshua Bloch dan Neal Gafter memasukkan varian berikut:
(Program ini ternyata menjadi program "Hello World" biasa-biasa saja.)
Dalam solusi untuk kusut, mereka menunjukkan hal berikut:
Sumber: Java: Menjalankan kode dalam komentar ?!
sumber
\u000d
dan bagian setelahnya harus memiliki highlight kode.// C:\user\...
yang mengarah ke kesalahan kompilasi karena\user
bukan urutan keluar Unicode yang valid.\u000d
disorot sebagian. Setelah menekan Ctrl + Shift + F karakter diganti dengan baris baru dan sisa baris dibungkus\u002A/
harus mengakhiri komentar.Karena ini belum dibahas, inilah penjelasan, mengapa terjemahan Unicode lolos terjadi sebelum pemrosesan kode sumber lainnya:
Gagasan di baliknya adalah memungkinkan terjemahan kode sumber Java tanpa kehilangan antar berbagai penyandian karakter. Saat ini, ada dukungan Unicode luas, dan ini tidak terlihat seperti masalah, tetapi saat itu tidak mudah bagi pengembang dari negara barat untuk menerima beberapa kode sumber dari rekannya di Asia yang berisi karakter Asia, buat beberapa perubahan ( termasuk mengkompilasi dan mengujinya) dan mengirim hasilnya kembali, semua tanpa merusak sesuatu.
Jadi, kode sumber Java dapat ditulis dalam penyandian apa saja dan memungkinkan berbagai karakter dalam pengidentifikasi, karakter dan
String
literal serta komentar. Kemudian, untuk mentransfernya tanpa kehilangan, semua karakter yang tidak didukung oleh target encoding digantikan oleh Unicode escapes mereka.Ini adalah proses yang dapat dibalik dan yang menarik adalah bahwa terjemahan dapat dilakukan oleh alat yang tidak perlu tahu apa-apa tentang sintaks kode sumber Java karena aturan terjemahan tidak bergantung padanya. Ini berfungsi sebagai terjemahan ke karakter Unicode mereka yang sebenarnya di dalam kompiler yang terjadi secara independen ke sintaksis kode sumber Java juga. Ini menyiratkan bahwa Anda dapat melakukan sejumlah langkah penerjemahan secara sewenang-wenang di kedua arah tanpa pernah mengubah arti kode sumber.
Ini adalah alasan untuk fitur aneh lain yang bahkan belum disebutkan:
\uuuuuuxxxx
sintaks:Ketika alat terjemahan keluar dari karakter dan menemukan urutan yang sudah keluar urutan, itu harus memasukkan tambahan
u
ke dalam urutan, konversi\ucafe
ke\uucafe
. Makna tidak berubah, tetapi ketika mengkonversi ke arah lain, alat harus menghapus satuu
dan mengganti hanya urutan yang mengandung satuu
oleh karakter Unicode mereka. Dengan begitu, bahkan pelolosan Unicode dipertahankan dalam bentuk aslinya saat mengonversi bolak-balik. Saya kira, tidak ada yang pernah menggunakan fitur itu ...sumber
native2ascii
sepertinya tidak menggunakan\uu...xxxx
sintaks,native2ascii
dimaksudkan untuk membantu menyiapkan bundel sumber daya dengan mengonversinya menjadi iso-latin-1 sepertiProperties.load
yang ditetapkan hanya untuk membaca latin-1. Dan di sana, aturannya berbeda, tidak ada\uuu…
sintaksis dan tidak ada tahap pemrosesan awal. Dalam file properti,property=multi\u000aline
memang sama denganproperty=multi\nline
. (Bertentangan dengan frasa “menggunakan pelepasan Unicode sebagaimana didefinisikan dalam bagian 3.3 dari Spesifikasi Bahasa Java ™” dari dokumentasi)\u
pelarian untuk menghasilkan karakter dalam kisaran U + 0000–007F. (Semua karakter seperti itu dapat diwakili secara asli oleh semua penyandian nasional yang relevan pada 1990-an — yah, mungkin kecuali beberapa karakter kontrol, tetapi Anda tetap tidak perlu menulis karakter Java.)Saya akan benar-benar menambahkan poin secara tidak efektif, hanya karena saya tidak dapat menahan diri dan belum melihatnya, bahwa pertanyaannya tidak valid karena mengandung premis tersembunyi yang salah, yaitu bahwa kode berada di komentar!
Dalam kode sumber Java \ u000d setara dengan setiap cara untuk karakter ASCII CR. Ini adalah akhiran garis, jelas dan sederhana, di mana pun itu terjadi. Pemformatan dalam pertanyaan ini menyesatkan, urutan karakter apa yang secara sintaksis bersesuaian adalah:
Oleh karena itu, jawaban yang paling benar adalah: kode dijalankan karena tidak ada dalam komentar; itu di baris berikutnya. "Kode pelaksana dalam komentar" tidak diizinkan di Jawa, seperti yang Anda harapkan.
Sebagian besar kebingungan berasal dari fakta bahwa highlighter sintaks dan IDE tidak cukup canggih untuk mempertimbangkan situasi ini. Mereka juga tidak memproses unicode lolos sama sekali, atau mereka melakukannya setelah parsing kode, bukan sebelumnya, seperti
javac
halnya.sumber
The
\u000d
melarikan diri berakhir komentar karena\u
lolos secara seragam diubah ke karakter Unicode yang sesuai sebelum program ini tokenized. Anda bisa menggunakan keduanya\u0057\u0057
sebagai ganti//
untuk memulai komentar.Ini adalah bug di IDE Anda, yang seharusnya menyoroti garis untuk membuat jelas bahwa
\u000d
mengakhiri komentar.Ini juga merupakan kesalahan desain dalam bahasa. Itu tidak dapat diperbaiki sekarang, karena itu akan merusak program yang bergantung padanya.
\u
escapes harus dikonversi ke karakter Unicode yang sesuai dengan kompilator hanya dalam konteks di mana "masuk akal" (string literal dan pengidentifikasi, dan mungkin tidak ada di tempat lain) atau mereka seharusnya dilarang untuk menghasilkan karakter dalam kisaran U + 0000–007F , atau keduanya. Salah satu dari semantik itu akan mencegah komentar dihentikan oleh\u000d
pelarian, tanpa mengganggu kasus-kasus di mana\u
pelarian berguna - perhatikan bahwa itu termasuk penggunaan\u
pelarian di dalam komentar sebagai cara untuk menyandikan komentar dalam skrip non-Latin, karena editor teks bisa mengambil pandangan yang lebih luas dari mana\u
escapes lebih penting daripada kompiler. (Saya tidak mengetahui ada editor atau IDE yang akan menampilkan\u
lolos sebagai karakter yang sesuai dalam apa pun konteksnya.)Ada kesalahan desain yang serupa dalam keluarga C, 1 di mana backslash-newline diproses sebelum batas komentar ditentukan, jadi misalnya
Saya membawa ini untuk menggambarkan bahwa itu mudah untuk membuat kesalahan desain khusus ini, dan tidak menyadari bahwa itu adalah kesalahan sampai sudah terlambat untuk memperbaikinya, jika Anda terbiasa berpikir tentang tokenization dan menguraikan cara programmer compiler berpikir tentang tokenization dan parsing. Pada dasarnya, jika Anda telah mendefinisikan tata bahasa formal Anda dan kemudian seseorang membuat kasus khusus sintaksis - trigraph, backslash-newline, pengkodean karakter Unicode yang sewenang-wenang dalam file sumber terbatas pada ASCII, apa pun - yang perlu dijepit, lebih mudah untuk tambahkan pass transformasi sebelum tokenizer daripada mendefinisikan ulang tokenizer untuk memperhatikan di mana masuk akal untuk menggunakan case khusus itu.
1 Untuk para pengendara: Saya tahu bahwa aspek C ini 100% disengaja, dengan alasan - Saya tidak mengada-ada - bahwa itu akan memungkinkan Anda untuk secara mekanis mencocokkan kode dengan garis panjang sewenang-wenang ke kartu berlubang. Itu masih keputusan desain yang salah.
sumber
\u
kurang absurd daripada keputusan untuk mengikuti jejak C dalam menggunakan nol terkemuka untuk notasi oktal. Walaupun notasi oktal kadang berguna, saya belum pernah mendengar ada yang mengartikulasikan argumen mengapa angka nol di depan adalah cara yang baik untuk menunjukkannya.\u
sebagai transformasi pra-tokenisasi jika dilarang untuk menghasilkan karakter dalam kisaran U + 0000..U + 007F. Ini kombinasi dari "ini bekerja di mana-mana" dan "ini alias karakter ASCII dengan signifikansi sintaksis" yang menurunkannya dari salah canggung menjadi salah.//
komentar single-line tidak ada . Dan karena C memiliki terminator pernyataan yang bukan baris baru, sebagian besar akan digunakan untuk string panjang, kecuali bahwa sejauh yang saya bisa menentukan "string literal concatenation" ada di sana dari K&R.Ini adalah pilihan desain yang disengaja yang akan kembali ke desain asli Jawa.
Untuk orang-orang yang bertanya "siapa yang ingin Unicode lolos dalam komentar?", Saya kira mereka adalah orang-orang yang bahasa ibunya menggunakan set karakter Latin. Dengan kata lain, itu melekat dalam desain asli Jawa bahwa orang dapat menggunakan karakter Unicode sewenang-wenang di mana pun legal dalam program Java, biasanya dalam komentar dan string.
Ini bisa dibilang kekurangan dalam program (seperti IDE) yang digunakan untuk melihat teks sumber bahwa program tersebut tidak dapat menafsirkan Unicode lolos dan menampilkan mesin terbang yang sesuai.
sumber
Saya setuju dengan @zwol bahwa ini adalah kesalahan desain; tapi saya bahkan lebih kritis terhadapnya.
\u
melarikan diri berguna dalam string dan char literal; dan itulah satu-satunya tempat yang seharusnya ada. Itu harus ditangani dengan cara yang sama seperti pelarian lainnya seperti\n
; dan"\u000A"
harus berarti persis"\n"
.Sama sekali tidak ada gunanya
\uxxxx
berkomentar - tidak ada yang bisa membacanya.Demikian pula, tidak ada gunanya menggunakan
\uxxxx
di bagian lain dari program ini. Satu-satunya pengecualian mungkin di API publik yang dipaksa mengandung beberapa karakter non-ascii - apa yang terakhir kali kita lihat itu?Para desainer memiliki alasan mereka pada tahun 1995, tetapi 20 tahun kemudian, ini tampaknya menjadi pilihan yang salah.
(pertanyaan kepada pembaca - mengapa pertanyaan ini terus mendapatkan suara baru? Apakah pertanyaan ini ditautkan dari tempat yang populer?)
sumber
int \u5431
ketika Anda bisa melakukannyaint 整
UTF-8
dukungan luas pada tahun 1995). Anda hanya perlu memanggil satu metode dan tidak ingin menginstal paket dukungan bahasa Asia dari sistem operasi Anda (ingat, tahun sembilan puluhan) untuk metode tunggal itu ...Satu-satunya orang yang dapat menjawab mengapa Unicode lolos adalah mereka adalah orang-orang yang menulis spesifikasi.
Alasan yang masuk akal untuk ini adalah bahwa ada keinginan untuk mengizinkan seluruh BMP sebagai karakter yang mungkin dari kode sumber Java. Ini menghadirkan masalah:
Ini sangat sulit ketika Unicode lolos memasuki keributan: itu menciptakan seluruh beban aturan lexer baru.
Jalan keluar yang mudah adalah dengan melakukan lexing dalam dua langkah: pertama mencari dan mengganti semua Unicode lolos dengan karakter yang diwakilinya, dan kemudian mengurai dokumen yang dihasilkan seolah-olah Unicode lolos tidak ada.
Sisi positifnya adalah mudah ditentukan, sehingga membuat spesifikasi lebih sederhana, dan mudah diterapkan.
Kelemahannya adalah, contoh Anda.
sumber