Pandangan mendalam mengenai jenis watak Java

Java versi 1.1 memperkenalkan sebilangan kelas untuk menangani watak. Kelas-kelas baru ini membuat pengabstrakan untuk menukar dari tanggapan khusus platform mengenai nilai watak menjadi nilai Unicode . Lajur ini melihat apa yang telah ditambahkan, dan motivasi untuk menambahkan kelas watak ini.

Taipkan char

Mungkin jenis asas yang paling disalahgunakan dalam bahasa C adalah jenis char . The char jenis teraniaya sebahagiannya kerana ia ditakrifkan sebagai 8 bit, dan sejak 25 tahun yang lalu, 8 bit juga telah ditakrifkan sebahagian dibahagikan terkecil memori pada komputer. Apabila anda menggabungkan fakta yang terakhir dengan fakta bahawa set watak ASCII didefinisikan agar muat dalam 7 bit, jenis char menjadikan jenis "universal" yang sangat sesuai. Selanjutnya, dalam C, penunjuk ke pemboleh ubah jenis char menjadi jenis penunjuk universal kerana apa-apa yang dapat dirujuk sebagai char juga dapat dirujuk sebagai jenis lain melalui penggunaan casting.

Penggunaan dan penyalahgunaan jenis char dalam bahasa C menyebabkan banyak ketidaksesuaian antara pelaksanaan penyusun, jadi dalam standard ANSI untuk C, dua perubahan khusus dibuat: Penunjuk universal ditakrifkan semula untuk memiliki jenis kekosongan, sehingga memerlukan eksplisit pengisytiharan oleh pengaturcara; dan nilai numerik watak dianggap ditandatangani, sehingga menentukan bagaimana mereka akan diperlakukan ketika digunakan dalam pengiraan numerik. Kemudian, pada pertengahan 1980-an, jurutera dan pengguna mengetahui bahawa 8 bit tidak mencukupi untuk mewakili semua watak di dunia. Malangnya, pada masa itu, C telah berakar supaya orang ramai tidak bersedia, mungkin juga tidak dapat, untuk menukar takrif charmenaip. Sekarang bergerak maju ke tahun 90-an, hingga awal awal Java. Salah satu dari banyak prinsip yang ditetapkan dalam reka bentuk bahasa Jawa adalah bahawa watak-wataknya adalah 16 bit. Pilihan ini menyokong penggunaan Unicode , cara standard untuk mewakili pelbagai jenis watak dalam pelbagai bahasa. Sayangnya, ini juga memberi jalan bagi berbagai masalah yang kini hanya dapat diperbaiki.

Apa wataknya pula?

Saya tahu saya berada dalam keadaan susah, saya mendapati diri saya bertanya soalan, "Jadi apa yang adalah watak tertentu?" Nah, watak adalah huruf, bukan? Sekumpulan huruf membentuk kata, perkataan membentuk ayat, dan sebagainya. Kenyataannya, bagaimanapun, adalah bahawa hubungan antara representasi watak pada layar komputer, yang disebut glyph , dengan nilai numerik yang menentukan bahawa glyph, disebut a code point, sama sekali tidak langsung.

Saya menganggap diri saya bertuah kerana menjadi penutur asli bahasa Inggeris. Pertama, kerana itu adalah bahasa umum sebilangan besar pihak yang menyumbang kepada reka bentuk dan pembangunan komputer digital moden; kedua, kerana ia mempunyai bilangan glyph yang agak kecil. Terdapat 96 aksara yang boleh dicetak dalam definisi ASCII yang boleh digunakan untuk menulis bahasa Inggeris. Bandingkan ini dengan bahasa Cina, di mana terdapat lebih daripada 20,000 glyph yang ditentukan dan definisi itu tidak lengkap. Sejak awal kod Morse dan Baudot, kesederhanaan keseluruhan (beberapa bilangan terbang, kekerapan statistik) dalam bahasa Inggeris menjadikannya lingua-franca dari era digital. Tetapi kerana jumlah orang yang memasuki era digital telah meningkat, begitu juga jumlah penutur bahasa Inggeris bukan asli. Apabila bilangannya bertambah,semakin banyak orang semakin tidak berminat untuk menerima bahawa komputer menggunakan ASCII dan hanya boleh berbahasa Inggeris. Ini sangat meningkatkan bilangan "watak" komputer yang perlu difahami. Akibatnya, bilangan glyph yang dikodkan oleh komputer terpaksa meningkat dua kali ganda.

Jumlah watak yang ada meningkat dua kali ganda apabila kod ASCII 7-bit yang dihormati dimasukkan ke dalam pengekodan watak 8-bit yang disebut ISO Latin-1 (atau ISO 8859_1, "ISO" menjadi Organisasi Piawaian Antarabangsa). Seperti yang mungkin anda kumpulkan dengan nama pengekodan, piawaian ini memungkinkan untuk menggambarkan banyak bahasa yang berasal dari latin yang digunakan di benua Eropah. Hanya kerana standard dibuat, namun tidak bermaksud dapat digunakan. Pada masa itu, banyak komputer sudah mulai menggunakan 128 "karakter" lain yang mungkin diwakili oleh watak 8-bit untuk beberapa kelebihan. Dua contoh penggunaan watak tambahan ini adalah IBM Personal Computer (PC), dan terminal komputer paling popular yang pernah ada, Digital Equipment Corporation VT-100.Yang terakhir hidup dalam bentuk perisian emulator terminal.

Masa sebenar untuk watak 8-bit pasti akan diperdebatkan selama beberapa dekad, tetapi saya memperbaikinya semasa pengenalan komputer Macintosh pada tahun 1984. Macintosh membawa dua konsep yang sangat revolusioner ke dalam pengkomputeran arus perdana: fon watak yang disimpan dalam RAM; dan WorldScript, yang dapat digunakan untuk mewakili karakter dalam bahasa apa pun. Sudah tentu, ini hanyalah salinan dari apa yang telah dihantar oleh Xerox pada mesin kelas Dandelion dalam bentuk sistem pemprosesan kata Star, tetapi Macintosh membawa set watak dan fon baru ini kepada penonton yang masih menggunakan terminal "bodoh" . Setelah dimulakan, penggunaan fon yang berbeza tidak dapat dihentikan - terlalu menarik bagi terlalu banyak orang. Menjelang akhir tahun 80-an,tekanan untuk menyeragamkan penggunaan semua watak ini muncul dengan pembentukan Unicode Consortium, yang menerbitkan spesifikasi pertamanya pada tahun 1990. Malangnya, pada tahun 80-an dan bahkan hingga tahun 90-an, jumlah set watak meningkat. Sebilangan kecil jurutera yang membuat kod watak baru pada masa itu menganggap standard Unicode yang baru dilancarkan, dan oleh itu mereka membuat pemetaan kod mereka sendiri untuk mesin terbang. Oleh kerana Unicode tidak diterima dengan baik, tanggapan bahawa hanya terdapat 128 atau paling banyak 256 watak yang ada pasti hilang. Selepas Macintosh, sokongan untuk fon yang berbeza menjadi ciri mustahak untuk pemprosesan kata. Lapan watak bit semakin pupus.80-an dan bahkan hingga tahun 90-an, bilangan set watak berlipat kali ganda. Sebilangan kecil jurutera yang membuat kod watak baru pada masa itu menganggap standard Unicode yang baru dilancarkan, dan oleh itu mereka membuat pemetaan kod mereka sendiri kepada mesin terbang. Oleh kerana Unicode tidak diterima dengan baik, tanggapan bahawa hanya terdapat 128 atau paling banyak 256 watak yang ada pasti hilang. Selepas Macintosh, sokongan untuk fon yang berbeza menjadi ciri mustahak untuk pemprosesan kata. Lapan watak bit semakin pupus.80-an dan bahkan hingga tahun 90-an, bilangan set watak berlipat kali ganda. Sebilangan kecil jurutera yang membuat kod watak baru pada masa itu menganggap standard Unicode yang baru dilancarkan, dan oleh itu mereka membuat pemetaan kod mereka sendiri kepada mesin terbang. Oleh kerana Unicode tidak diterima dengan baik, tanggapan bahawa hanya terdapat 128 atau paling banyak 256 watak yang ada pasti hilang. Selepas Macintosh, sokongan untuk fon yang berbeza menjadi ciri mustahak untuk pemprosesan kata. Lapan watak bit semakin pupus.tanggapan bahawa hanya terdapat 128 atau paling banyak 256 watak yang ada sudah pasti hilang. Selepas Macintosh, sokongan untuk fon yang berbeza menjadi ciri mustahak untuk pemprosesan kata. Lapan watak bit semakin pupus.tanggapan bahawa hanya terdapat 128 atau paling banyak 256 watak yang ada sudah pasti hilang. Selepas Macintosh, sokongan untuk fon yang berbeza menjadi ciri mustahak untuk pemprosesan kata. Lapan watak bit semakin pupus.

Java dan Unicode

Saya memasuki cerita pada tahun 1992 ketika saya bergabung dengan kumpulan Oak (Bahasa Jawa disebut Oak ketika pertama kali dikembangkan) di Sun. Char jenis asasditakrifkan sebagai 16 bit yang tidak ditandatangani, satu-satunya jenis yang tidak ditandatangani di Java. Alasan untuk watak 16-bit adalah bahawa ia akan menyokong perwakilan watak Unicode, sehingga menjadikan Java sesuai untuk mewakili rentetan dalam bahasa apa pun yang disokong oleh Unicode. Tetapi dapat mewakili rentetan dan dapat mencetaknya selalu menjadi masalah yang berasingan. Memandangkan sebahagian besar pengalaman dalam kumpulan Oak berasal dari sistem Unix dan sistem yang berasal dari Unix, set watak yang paling selesa adalah, sekali lagi, ISO Latin-1. Juga, dengan peninggalan kumpulan Unix, sistem Java I / O dimodelkan sebagian besar pada abstraksi aliran Unix di mana setiap peranti I / O dapat diwakili oleh aliran bait 8-bit. Gabungan ini meninggalkan kesalahan dalam bahasa antara peranti input 8-bit dan watak-watak Java 16-bit. Oleh itu,di mana sahaja rentetan Java mesti dibaca atau ditulis ke aliran 8-bit, terdapat sedikit kod, peretasan, untuk secara ajaib memetakan watak 8 bit menjadi unicode 16 bit.

Dalam versi Java Kit Pengembang (JDK) 1.0, penggodaman input ada di DataInputStreamkelas, dan penggodaman output adalah keseluruhan PrintStreamkelas. (Sebenarnya ada kelas input yang disebut TextInputStreamdalam rilis alpha 2 Java, tetapi digantikan oleh DataInputStreamhack dalam rilis sebenarnya.) Ini terus menimbulkan masalah untuk memulai programmer Java, karena mereka sangat mencari Java yang setara dengan C fungsi getc(). Pertimbangkan program Java 1.0 berikut:

import java.io. *; palsu kelas awam {public static void main (String args []) {FileInputStream fis; DataInputStream dis; char c; cuba {fis = FileInputStream baru ("data.txt"); dis = DataInputStream baru (fis); sementara (benar) {c = dis.readChar (); System.out.print (c); System.out.flush (); jika (c == '\ n') pecah; } fis.tutup (); } tangkapan (Pengecualian e) {} System.exit (0); }}

Pada pandangan pertama, program ini nampaknya membuka fail, membacanya satu karakter pada satu masa, dan keluar ketika baris pertama dibaca. Walau bagaimanapun, dalam praktiknya, apa yang anda dapat adalah output sampah. Dan alasan anda menjadi sampah ialah readChar membaca watak Unicode 16-bit dan System.out.printmencetak apa yang dianggapnya adalah watak-watak 8-bit ISO Latin-1. Namun, jika anda mengubah program di atas untuk menggunakan fungsi readLineDataInputStream , ia akan berfungsi kerana kod di readLinemembaca format yang ditentukan dengan anggukan lulus ke spesifikasi Unicode sebagai "UTF-8 yang diubah." (UTF-8 adalah format yang ditentukan oleh Unicode untuk mewakili watak Unicode dalam aliran input 8-bit.) Jadi, situasi di Java 1.0 adalah bahawa rentetan Java terdiri daripada watak Unicode 16-bit, tetapi hanya ada satu pemetaan yang memetakan Aksara Latin-1 ISO ke dalam Unicode. Nasib baik, Unicode mendefinisikan halaman kod "0" - iaitu, 256 aksara yang 8 bit atas semuanya sifar - untuk sama persis dengan set ISO Latin-1. Oleh itu, pemetaan itu cukup remeh, dan selagi anda hanya menggunakan fail watak ISO Latin-1, anda tidak akan menghadapi masalah ketika data meninggalkan fail, dimanipulasi oleh kelas Java, dan kemudian ditulis semula ke fail .

Terdapat dua masalah dengan memasukkan kod penukaran input ke dalam kelas ini: Tidak semua platform menyimpan fail multibahasa mereka dalam format UTF-8 yang diubah; dan semestinya, aplikasi di platform ini tidak semestinya mengharapkan watak bukan Latin dalam bentuk ini. Oleh itu, sokongan pelaksanaan tidak lengkap, dan tidak ada cara mudah untuk menambahkan sokongan yang diperlukan dalam keluaran kemudian.

Java 1.1 dan Unicode

The Java 1.1 release introduced an entirely new set of interfaces for handling characters, called Readers and Writers. I modified the class named bogus from above into a class named cool. The cool class uses an InputStreamReader class to process the file rather than the DataInputStream class. Note that InputStreamReader is a subclass of the new Reader class and the System.out is now a PrintWriter object, which is a subclass of the Writer class. The code for this example is shown below:

import java.io.*; public class cool { public static void main(String args[]) { FileInputStream fis; InputStreamReader irs; char c; try { fis = new FileInputStream("data.txt"); irs = new InputStreamReader(fis); System.out.println("Using encoding : "+irs.getEncoding()); while (true) { c = (char) irs.read(); System.out.print(c); System.out.flush(); if (c == '\n') break; } fis.close(); } catch (Exception e) { } System.exit(0); } } 

The primary difference between this example and the previous code listing is the use of the InputStreamReader class rather than the DataInputStream class. Another way in which this example is different from the previous one is that there is an additional line that prints out the encoding used by the InputStreamReader class.

The important point is that the existing code, once undocumented (and ostensibly unknowable) and embedded inside the implementation of the getChar method of the DataInputStream class, has been removed (actually its use is deprecated; it will be removed in a future release). In the 1.1 version of Java, the mechanism that performs the conversion is now encapsulated in the Reader class. This encapsulation provides a way for the Java class libraries to support many different external representations of non-Latin characters while always using Unicode internally.

Of course, like the original I/O subsystem design, there are symmetric counterparts to the reading classes that perform writing. The class OutputStreamWriter can be used to write strings to an output stream, the class BufferedWriter adds a layer of buffering, and so on.

Trading warts or real progress?

The somewhat lofty goal of the design of the Reader and Writerclasses was to tame what is currently a hodge-podge of representation standards for the same information by providing a standard way of converting back and forth between the legacy representation -- be it Macintosh Greek or Windows Cyrillic -- and Unicode. So, a Java class that deals with strings need not change when it moves from platform to platform. This might be the end of the story, except that now that the conversion code is encapsulated, the question arises as to what that code assumes.

Semasa meneliti ruangan ini, saya teringat petikan terkenal dari seorang eksekutif Xerox (sebelum itu adalah Xerox, ketika itu adalah Syarikat Haloid) mengenai mesin fotokopi itu berlebihan kerana cukup mudah bagi seorang setiausaha untuk memasukkan sekeping kertas karbon ke dalam mesin taipnya dan membuat salinan dokumen semasa dia membuat yang asli. Sudah tentu, apa yang jelas di belakang adalah mesin fotokopi memberi manfaat kepada orang yang menerima dokumen lebih banyak daripada yang dihasilkan oleh orang yang menghasilkan dokumen. JavaSoft telah menunjukkan kekurangan pandangan yang sama tentang penggunaan kelas pengekodan dan penyahkodan watak dalam reka bentuk bahagian sistem ini.