По-задълбочен поглед върху типа символи на Java

Версията на Java 1.1 въвежда редица класове за работа с символи. Тези нови класове създават абстракция за преобразуване от специфично за платформата понятие за символни стойности в Unicode стойности. Тази колона разглежда добавеното и мотивацията за добавяне на тези класове знаци.

Въведете char

Може би най-злоупотребяваният основен тип в езика C е типът char . Типът char се злоупотребява отчасти, защото е дефиниран на 8 бита, а за последните 25 години 8 бита също са дефинирали най-малкия неделим парче памет на компютрите. Когато комбинирате последния факт с факта, че наборът от символи ASCII е дефиниран да се побере в 7 бита, типът char прави много удобен "универсален" тип. Освен това, в C, указател към променлива от тип char се превърна в универсален тип указател, защото всичко, което може да бъде посочено като char, също може да бъде посочено като всеки друг тип чрез използването на отливка.

Използването и злоупотребата с типа char в езика C доведе до много несъвместимости между изпълнението на компилатора, така че в стандарта ANSI за C бяха направени две специфични промени: Универсалният указател беше предефиниран, за да има тип void, като по този начин се изисква изрично декларация от програмиста; и се смяташе, че числовата стойност на символите е подписана, като по този начин се определя как те ще бъдат третирани, когато се използват в числови изчисления. След това, в средата на 80-те, инженери и потребители разбраха, че 8 бита са недостатъчни, за да представят всички герои в света. За съжаление по това време C беше толкова укрепен, че хората не искаха, може би дори не можеха да променят дефиницията на charТип. Сега преминете напред към 90-те, към ранното начало на Java. Един от многото принципи, залегнали в дизайна на езика Java, беше, че символите ще бъдат 16 бита. Този избор поддържа използването на Unicode , стандартен начин за представяне на много различни видове знаци на много различни езици. За съжаление, той също така постави началото на различни проблеми, които едва сега се решават.

Какво изобщо е герой?

Знаех, че имам проблеми, когато се озовах да задам въпроса „И така, какво е герой?“ Е, героят е буква, нали? Куп букви съставят дума, думите образуват изречения и т.н. Реалността обаче е, че връзката между представянето на даден знак на компютърен екран, наречен негов глиф , към числовата стойност, която указва, че глифът, наречен а code point, всъщност изобщо не е ясна.

Смятам, че съм късметлия, че съм носител на английски език. Първо, защото това беше общият език на значителен брой от онези, които допринесоха за проектирането и развитието на съвременния цифров компютър; второ, защото има относително малък брой глифи. В дефиницията на ASCII има 96 знака за печат, които могат да се използват за писане на английски език. Сравнете това с китайския, където има дефинирани над 20 000 глифа и това определение е непълно. От ранното начало в кода на Морс и Бодо, общата простота (малко глифове, статистическа честота на поява) на английския език го прави лингва-франка на дигиталната ера. Но тъй като броят на хората, които навлизат в дигиталната ера, се увеличава, нараства и броят на чуждестранните англоговорящи. С нарастването на числата,все повече и повече хора все по-склонни да приемат, че компютрите използват ASCII и говорят само английски. Това значително увеличи броя на „знаците“ компютри, необходими за разбиране. В резултат броят на глифите, кодирани от компютрите, трябваше да се удвои.

Броят на наличните знаци се удвои, когато почтеният 7-битов ASCII код беше включен в 8-битово кодиране на символи, наречено ISO Latin-1 (или ISO 8859_1, като "ISO" е Международната организация по стандартизация). Както може би сте разбрали от кодиращото име, този стандарт позволява представянето на много от изведените от латиница езици, използвани на европейския континент. Само защото стандартът е създаден, обаче не означава, че е използваем. По това време много компютри вече бяха започнали да използват останалите 128 „знака“, които може да бъдат представени от 8-битов знак с някаква предимство. Двата оцелели примера за използването на тези допълнителни символи са IBM Personal Computer (PC) и най-популярният компютърен терминал някога, Digital Equipment Corporation VT-100.Последният живее под формата на софтуер за емулатор на терминали.

Действителното време на смъртта на 8-битовия символ без съмнение ще бъде обсъждано в продължение на десетилетия, но аз го определям при представянето на компютъра Macintosh през 1984 г. Macintosh внесе две много революционни концепции в масовите изчисления: шрифтове на символи, които се съхраняват в RAM; и WorldScript, които могат да се използват за представяне на символи на всеки език. Разбира се, това беше просто копие на това, което Xerox доставяше на машините си от клас Dandelion под формата на система за обработка на текст Star, но Macintosh донесе тези нови набори от символи и шрифтове на аудитория, която все още използва „тъпи“ терминали . Веднъж започнало, използването на различни шрифтове не можеше да бъде спряно - просто беше твърде привлекателно за твърде много хора. До края на 80-те,натискът за стандартизиране на използването на всички тези знаци се засили с формирането на консорциума Unicode, който публикува първата си спецификация през 1990 г. За съжаление, през 80-те и дори през 90-те години броят на наборите символи се умножи. Много малко от инженерите, които създаваха нови кодове на символи по това време, смятаха, че зараждащият се стандарт Unicode е жизнеспособен и затова те създадоха свои собствени картографирания на кодове към глифове. Така че, докато Unicode не беше добре приет, идеята, че има само 128 или най-много 256 символа, определено беше изчезнала. След Macintosh поддръжката на различни шрифтове се превърна в задължителна функция за текстообработка. Осем битови знака изчезваха.80-те и дори през 90-те години броят на наборите символи се умножи. Много малко от инженерите, които създаваха нови кодове на символи по това време, смятаха, че зараждащият се стандарт на Unicode е жизнеспособен и затова те създадоха свои собствени картографирания на кодове към глифи. Така че, докато Unicode не беше добре приет, идеята, че има само 128 или най-много 256 символа, определено беше изчезнала. След Macintosh поддръжката на различни шрифтове се превърна в задължителна функция за текстообработка. Осем битови знака изчезваха.80-те и дори през 90-те години броят на наборите символи се умножи. Много малко от инженерите, които създаваха нови кодове на символи по това време, смятаха, че зараждащият се стандарт на Unicode е жизнеспособен и затова те създадоха свои собствени картографирания на кодове към глифи. Така че, докато Unicode не беше добре приет, идеята, че има само 128 или най-много 256 символа, определено беше изчезнала. След Macintosh поддръжката на различни шрифтове се превърна в задължителна функция за текстообработка. Осем битови знака изчезваха.идеята, че са налични само 128 или най-много 256 знака, определено е изчезнала. След Macintosh поддръжката на различни шрифтове се превърна в задължителна функция за текстообработка. Осем битови знака изчезваха.идеята, че са налични само 128 или най-много 256 знака, определено беше изчезнала. След Macintosh поддръжката на различни шрифтове се превърна в задължителна функция за текстообработка. Осем битови знака изчезваха.

Java и Unicode

Влязох в историята през 1992 г., когато се присъединих към групата Oak (езикът Java се нарича Oak, когато беше разработен за първи път) в Sun. Основният тип charбеше дефиниран като 16 неподписани бита, единственият неподписан тип в Java. Обосновката за 16-битовия символ беше, че той ще поддържа всяко представяне на символи на Unicode, като по този начин прави Java подходяща за представяне на низове на всеки език, поддържан от Unicode. Но възможността да представите низа и възможността да го отпечатате винаги са били отделни проблеми. Като се има предвид, че по-голямата част от опита в групата Oak идва от системи Unix и системи, получени от Unix, най-удобният набор от символи отново беше ISO Latin-1. Също така, с наследството на Unix на групата, I / O системата Java е моделирана до голяма степен на абстракцията на потока Unix, при което всяко I / O устройство може да бъде представено от поток от 8-битови байтове. Тази комбинация остави нещо като грешка в езика между 8-битово устройство за въвеждане и 16-битовите символи на Java. По този начин,навсякъде, където Java низовете трябваше да бъдат прочетени от или записани в 8-битов поток, имаше малък бит код, хак, за магическо картографиране на 8 битови символи в 16 битов unicode.

Във версиите 1.0 на Java Developer Kit (JDK) входният хак беше в DataInputStreamкласа, а изходният хак беше целият PrintStreamклас. (Всъщност имаше входящ клас, наречен TextInputStreamв алфа 2 изданието на Java, но той беше изместен от DataInputStreamхакването в действителната версия.) Това продължава да създава проблеми за начинаещите програмисти на Java, тъй като те отчаяно търсят еквивалента на Java на C функция getc(). Помислете за следната програма Java 1.0:

импортиране на java.io. *; публичен клас фалшив {публична статична празнота main (String args []) {FileInputStream fis; DataInputStream dis; char c; опитайте {fis = new FileInputStream ("data.txt"); dis = нов DataInputStream (fis); докато (вярно) {c = dis.readChar (); System.out.print (c); System.out.flush (); ако (c == '\ n') почивка; } fis.close (); } catch (Изключение e) {} System.exit (0); }}

На пръв поглед тази програма изглежда ще отвори файл, ще го прочете по един символ и ще излезе, когато бъде прочетен първият нов ред. На практика обаче получавате боклуци. И причината да получавате боклуци е, че readChar чете 16-битови Unicode символи и System.out.printотпечатва това, което предполага, че са ISO-1 8-битови символи. Ако обаче промените горната програма да използва функцията readLine на DataInputStream, тя ще изглежда да работи, защото кодът в readLineчете формат, който е дефиниран с преминаващ ким към спецификацията на Unicode като „модифициран UTF-8“. (UTF-8 е форматът, който Unicode посочва за представяне на Unicode символи в 8-битов входен поток.) ​​Така че ситуацията в Java 1.0 е, че Java низовете са съставени от 16-битови Unicode символи, но има само едно картографиране, което съответства ISO латиница-1 символа в Unicode. За щастие Unicode дефинира кодовата страница „0“ - тоест 256-те знака, чиито горни 8 бита са нула - да отговаря точно на набора ISO Latin-1. По този начин картографирането е доста тривиално и стига да използвате само символни файлове ISO Latin-1, няма да имате никакви проблеми, когато данните оставят файл, манипулират се от клас Java и след това се пренаписват във файл .

There were two problems with burying the input conversion code into these classes: Not all platforms stored their multilingual files in modified UTF-8 format; and certainly, the applications on these platforms didn't necessarily expect non-Latin characters in this form. Therefore, the implementation support was incomplete, and there was no easy way to add the needed support in a later release.

Java 1.1 and 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.

Докато изследвах тази рубрика, ми напомни известен цитат от изпълнителен директор на Xerox (преди това беше Xerox, когато беше Haloid Company) за фотокопирната машина, която е излишна, защото за секретарката беше доста лесно да постави парче въглеродна хартия в нейната пишеща машина и направете копие на документ, докато тя е създавала оригинала. Разбира се, онова, което е очевидно отзад, е, че машината за фотокопиране е в полза на лицето, което получава документ, много повече, отколкото на лицето, генериращо документ. JavaSoft показа подобна липса на разбиране за използването на класовете за кодиране и декодиране на знаци при тяхното проектиране на тази част от системата.