Простые типы

В

данной главе приводятся основные сведения о работе с типами языка Java. Вы прочитаете обо всех восьми простых типах — или примитивных типах, как их иногда называют — языка Java. Вы также ознакомитесь на примерах, как работать с каждым из этих типов.

Простой тип (Simple Type) в Java — это тип, который не инкапсулирован в какой — либо класс. Как вы знаете, практически все в Java является классами — кроме этих восьми простых типов.

Но существуют и классы, являющиеся оболочками для каждого из этих типов. Имена всех этих классов начинаются с заглавных букв (Boolean, Integer, Float, Double И т. д.) Применение классовых типов влечет чуть больше затрат, чем для про­стых типов, но классы в Java настолько хорошо оптимизированы, что в большинстве случаев этого увеличения затрат можно не опасаться. Преимущество классовых ти­пов по сравнению с простыми типами состоит в том, что у них есть встроенные ме­тоды для выполнения полезных задач, связанных с этим классом. Наиболее нагляд­ный пример — возможность преобразования целого числа или числа с плавающей точкой в строку.

Программа, приведенная в данной главе в качестве примера, предоставит вам ве­ликолепную возможность для установки обработчиков событий, возникающих у ви­зуальных элементов управления ваших приложений. Ее можно найти в сопровожда­ющих книгу материалах, под именем CallMyTypes. Кроме того, в данной главе про­должается обсуждение классов и методов, начатое в предыдущей главе.

Вообще говоря, тема данной главы охватывает не только типы, но и многие об­щие вопросы программирования. Поэтому давайте перейдем от слов к делу: начнем изучение базовых типов языка Java.

Базовые типы языка

Java, будучи хорошо определенным, строго типизированным языком, элегантно решает всю проблему типов. Существует только восемь типов, и каждый из них, по сути, очень прост. В таблице 9.1 приведен обзор типов, обсуждаемых в данной главе.

Каждый из этих типов всегда занимает определенное и постоянное количество битов. У вас никогда не возникнет ситуация, возможная в C++ Или в Pascal, когда целое число занимает при одних обстоятельствах 16 битов, при других — 32 бита, и, возможно, в некоторых случаях — 64 бита. Java-тип Int в любом случае, на любой платформе занимает 32 бита. Вы также можете не беспокоиться о наличии знака у

Какого-либо конкретного значения. Все числовые типы имеют знак, т. е. могут быть положительными или отрицательными. В Java не бывает целых чисел без знака.

Ослы ему славу по нотам поют, устроено!

Козлы бородою дорогу метут!.. Как тут все здорово

Таблица 9.1. Восемь типов данных, их размеры и диапазоны значений

Тип

Размер

Диапазон или примечание

Boolean

По-разному, обычно 32

Только false или true

Byte

8 битов

-127 .. 127

Char

16 битов

Любой символ Unicode или стандартный символ

Short

16 битов

-32 768 .. 32 767

Int

32 бита

-2 147 483 648 .. 2 147 483 647

Long

64 бита

-922 337 2036 854 775 808 .. 9 223 372 036 854 775 807

Float

32 бита

-3.4×103β.. 3.4×103β (6-7 значащих цифр)

Double

64 бита

-1.7×10308 .. 1.7×103°θ (15-16 значащих цифр)

Как видно из таблицы, имеются простые типы для 8-, 16-, 32- и 64-битовых це­лых чисел или, как их иногда называют, Скалярных чисел (Scalar Numbers‘). Целые типы (byte, short, int и long) могут содержать целые числа вроде 1, 5, 25, -15 или 0. Типы с большим количеством битов могут содержать большие числа.

Типы с плавающей точкой (float и double) отличаются от целых типов (byte, short, int и long) тем, что у них есть цифры после десятичной точки. Например, 3.2 является числом с плавающей точкой, а число 16 — целым.

Тип char занимает не 8, а 16 битов. Это значит, что он предназначен для хране­ния символов Unicode, которые охватывают разные языковые наборы символов, вроде китайских иероглифов. В старые добрые времена программирования в DOS иероглифы было трудно закодировать, поскольку тип char занимал только 8 битов и поэтому мог содержать лишь 256 символов. Иероглифов тысячи, и чтобы закоди­ровать их все, нужно было разработать новый стандарт. Этот стандарт называется Unicode, и Java полностью поддерживает его.

Тип boolean предназначен для хранения только двух значений: true или false. Несмотря на это, этот тип обычно занимает 32 бита, поскольку в современных ком­пьютерах именно таков обычный размер слова. Но вопрос, сколько битов занимают значения типа boolean, является чисто академическим, т. к. в них может храниться только одно из двух значений и ничего больше. Далее в этой главе я еще вернусь к этому вопросу, более подробно и более понятно.

Класс, использующий все типы

Теперь, после краткого ознакомления со всеми типами языка, можно пригля­деться к ним более пристально. Для начала рассмотрим класс, использующий наи­более фундаментальные свойства каждого типа. Этот класс приведен в листинге 9.1.

Листинг 9.1. Класс MyTypes1 демонстрирующий использование всех базовых типов Java

Public class MyTypes

{

∕∕ Boolean: это простой тип, он может принимать значения только true // или false. В него невозможно записать целое число или символ, boolean myBool;

//Символы вроде, A,, 1E’, *В*. Для хранения строк пользуйтесь классом String char myChar;

// Целые числа

Byte myByte; //8 битов

Short myShort; // 16 битов

Int myInt; // 32 бита

Long my Long; //64 бита, при присваивании литералов

// дописывайте букву L: MyLong = 2L;

// Числа с плавающей точкой

Float myFloat; // 32 бита, при присваивании литералов // дописывайте букву F: myFloat = 2. OF;

Double myDouble; // 64 бита

Public MyTypes ()

{

MyBool = true;

MyChar = ,A’ ;

MyByte = Byte. MAX_VALUE; ∕∕ 127;

MyShort = Short. МАХ_VALUE; ∕∕ 32767;

MyInt = Integer. MAX_VALUE; ∕∕ 2147483647;

MyLong = 9223372036854775807L;∕∕ B конце литералов должна быть // буква 1 или L

MyFloat = 1.0f; // В конце литералов должна быть буква f или F

MyDouble = Double. МАХ_VALUE;

}

Public byte getMyByte() {

Return myByte;

}

Public String getMinByteAsString()

{

Return Byte. toStrIng(Byte-MIN-VALUE);

)

Public int getMyInt()

{

Return my Int;

}

Public String getMinlntegerAsString()

{

Return Integer. toString(Integer. MIN_VALUE);

}

Public long getMyLong()

{

Return myLong;

)

Public String getMinLongAsString()

(

Return Long. toStrIng(Long-MIN-VALUE);

Public short getMyShort()

{

Return myShort;

}

Public String getMinShortAsString()

{

Return Integer. toString(Short. MIN_VALUE);

)

Public float getMyFloat()

{

Return myFloat;

}

Public String getMinFloatAsString()

{

Return Float. toString(Float. MIN_VALUE);

}

Public double getMyDouble()

{

Return myDouble;

}

Public String getMinDoubleAsString ()

{

Return Double. toString(Double. MIN_VALUE);

}

Этот класс предназначен для демонстрации использования простых типов в Java. Кроме того, данный код является примером практической работы с классами и методами. Давайте внимательно рассмотрим этот код и посмотрим, может ли он для чего-либо пригодиться.

Объявление простых типов

Класс начинается с объявления нескольких переменных:

∕∕ Boolean: это простой тип, он может принимать значения только true // или false. В него невозможно записать целое число или символ, boolean myBool;

//Символы вроде ‘A,,’B’,’B’.Для хранения строк пользуйтесь классом String char myChar;

// Целые числа byte myByte; / / 8 битов

Short myShort; // 16 битов

Int myInt; // 32 бита

Long my Long; //64 бита, при присваивании литералов

// дописывайте букву L: MyLong = 2L;

// Числа с плавающей точкой

Float myFloat; // 32 бита, при присваивании литералов // дописывайте букву F: myFloat = 2. OF;

Double myDouble; //64 бита

Первое значение имеет тип boolean, второе — тип char, третье — byte, четвер­тое — shɔrt, пятое — int, шестое — long, седьмое — float, и восьмое — double. Это все простые типы, доступные в Java*.

Hy вот, переменные всех простых типов объявлены, и что же теперь с ними де­лать? Ответ на этот вопрос довольно сложен и занимает почти весь остаток данной главы. Исследование его начинается в следующем разделе, в котором приведен кон­структор ДЛЯ Класса MyTypes.

Инициализация простых типов

Первый серьезный участок кода рассматриваемого класса инициализирует все значения в конструкторе класса:

public mytypes()
{
mybool = true;
my char = ,a, ;
mybyte = byte.max_value;
myshort = short.max_value;
mylnt = integer.max-value;
mylong = 9223372036854775807l;
myfloat = 1.0f; ∕∕ b конце
mydouble = double-max-value;
u 127;
h 32767;
∕∕ 2147483647;
∕∕ b конце литералов должна быть // буква 1 или l
литералов должна быть буква £ или f

Переменным myBool и myChar присвоены значения литералов. Литерал {literal) — Это просто запись некоторого значения, например, строки, символа или числа. Литералу невозможно присвоить значение, поскольку это не переменная. myBool является переменной, a true — это значение литерала. myChar является перемен­ной, а вот, a, — это значение литерала. myByte представляет собой переменную, а число 127 — это значение литерала, string — это классовый тип, а строковый лите­рал записывается следующим образом: "Это строковый литерал".

Код в классе MyTypes инициализирует переменную типа byte максимально воз­можным значением, которое равно 127:

MyByte = Byte-MAX-VALUE; // 127

Конечно, можно было просто написать и так: myByte = 127. Присваивание пе­ременной myByte значения литерала 127 приведет точно к такому же результату, что и приведенный выше фрагмент кода. Но я использовал поле мах_value класса Byte, которое возвращает константу, равную максимально допустимому для байта числу. Ясно, что этот класс может возвращать и минимальное значение млгvalue. Единственное назначение использования мах_value состоит в том, что этот способ получения максимального значения байта легче запоминается. В языках C++ Или Pascal аналогичные функции применяются отчасти потому, что некоторые типы, на­пример целые числа, имеют различный размер в зависимости от используемой платформы; Но с Java об этом можно не беспокоиться, и данное средство использу­ется чисто автоматически.

Можно написать просто myByte = By te. мах_value, не пользуясь оператором new для создания экземпляра класса Byte. Это возможно, поскольку переменная MAX—value объявлена как статическая. В частности, в исходном коде Java эти значе­ния определены следующим образом:

Public final class Byte extends Number Inplements Conparable

{

∕**

* Минимальное значение, которое может принимать тип Byte.

*/

Public static final byte MIN_VALUE = -128;

∕**

* Максимальное значение, которое может принимать тип Byte.

*/

Public static final byte MAX_VALUE = 127;

Зачем в заголовке класса должно присутствовать ключевое слово extends, вы уз­нали в предыдущей главе, а о реализации интерфейсов кратко было рассказано в главе 7. Здесь эта строка приведена просто для того, чтобы вы могли видеть, что это объявление класса Byte.

Как видите, переменная min_value объявлена как простая переменная типа byte:

Byte MIN_VALUE = -128;

Это понятно. Но что это за слова "public static final"? Что они означают?

Из предыдущей главы вы уже знаете, что слово public означает, что переменная доступна извне пакета, в котором объявлен класс. Конечно, в данном случае это крайне важно, поскольку исходный Java-код находится не в том же каталоге, что и ваша программа.

Слово static означает, что к этой переменной можно получить доступ без со­здания экземпляра класса. Другими словами, вовсе не обязательно писать

Byte myBy te = new Byte () ;

Byte myVariable = myByte. MAX_VALUE;

Вместо этого можно написать byte myVariable = Byte. MAX_VALUE;

Обычно доступ к полям или методам класса невозможен без создания экземпля­ра этого класса. Это возможно лишь при доступе к методам или полям, которые объявлены как static.

Еще раз обратите внимание на, возможно, слишком уж тонкое взаимодействие между типом byte и классом Byte. Имена классов всегда должны начинаться с боль­шой буквы, а имена простых типов — с маленькой буквы. Это не нормально — по­жалуй, это даже слабость языка — но так уж заведено. В Java многое зависит от реги­стра букв (на мой взгляд, даже слишком многое)!

А что значит final? Это ключевое слово применяется, когда необходимо объя­вить, что некоторое значение не может и не должно изменяться. Во многих других языках программирования для этой же цели используется слово const. В Java, по не вполне понятным мне причинам, выбрано слово final.

примечаниеПравила, связанные со словом final, достаточно просты:

Класс, объявленный как final, не может быть расширен, т. е. от него нельзя со­здать подкласс. От него невозможно наследование. У него не может быть произ­водных классов.

■ Метод, объявленный как final, не может быть перекрыт. В этом смысле Java ве­дет себя не так, как языки, подобные Pascal или С/С++. Все методы считаются не­явно объявленными как виртуальные, если они явно не отмечены как окончатель­ные (т. е. final). Окончательный метод — это не просто невиртуальный метод. В производном классе нельзя объявить метод с тем же именем. При компиляции та­кой программы возникнет ошибка. В главе 8 приведен соответствующий пример.

■ Переменная, объявленная как final, соответствует тому, что в других языках про­граммирования называется константой. Она не может быть изменена. Если вы ни­чего присвоите переменной final, она называется пустой переменной. Она ни­когда не будет иметь значения.

Хотя об этом и упоминалось ранее, я хочу напомнить, как найти объявление класса Byte. В JBuilder это сделать легко. В исходном коде вашей программы най­дите интересующую вас переменную или тип. Например, найдите то место в вашем коде, где написано Byte. MAX_VALUE. Выделите курсором слово Byte, щелкните на нем правой кнопкой мыши и в появившемся меню выберите пункт Find Definition (в старых версиях продукта это был пункт Browse Symbol). Будет автоматически заг­ружен нужный исходный файл, а в нем будет показано нужное место.

При просмотре исходного файла из JDK вы увидите в IDE JBuilder закладку с надписью Doc. Щелкнув на ней, вы увидите документацию на тот класс, который вы просматриваете в данный момент. Как правило, doc-файлы существуют для всех классов, присутствующих в JDK. Но для создаваемых вами классов документации не будет, пока вы явно не создадите ее. Далее в этой книге подробно описывается сред­ство, называемое Javadoc, с помощью которого можно создать такую документацию.

Последние абзацы подчеркивают две важные мысли:

■ JBuilder предоставляет мощную возможность просмотра исходного кода.

■ Java поставляется вместе с исходным кодом. В нем нет никаких секретов. Ис­ходный код существует для всего, и вы получаете его бесплатно, просто выгру­зив JDK.

Кроме max_value и min_value, в классе Byte присутствуют и другие полезные вещи, в том числе и вездесущий метод tostring(), преобразующий байт в строку string. Например, он может преобразовать число 127 в строку "127". Как это сде­лать, будет показано ниже в этой главе.

В JBuilder имеется мощное средство CodeInsight, с помощью которого можно ис­следовать класс Byte. Вообще говоря, с его помощью можно просмотреть любой ис­ходный код Java, и в принципе любой исходный код, в том числе и написанный вами. В частности, с помощью CodeInsight вы можете просмотреть все методы клас­са Byte.

Для применения CodeInsight напечатайте имя экземпляра класса или имя класса и введите точку. Например, напечатайте в своем исходном коде слово Byte, а за ним точку. Теперь нажмите Ctrl+Alt+H или Ctrl+пробел, в зависимости от типа исполь­
зуемой вами настройки клавиатуры. (Чтобы узнать, какое сочетание клавиш ис­пользовать, выберите пункт меню Tools ∣ Editor Options. На странице редактора щел­кните на кнопке Customize. Сочетания клавиш сгруппированы по алфавиту, так что вы найдете CodeInsight в разделе С.) После нажатия нужных клавиш появится окно, отображающее все методы вашего класса (см. рис. 9.1). Этот список создается дина­мически, поэтому он доступен и для SDK, и для объявленных вами классов. В нем всегда отражается текущее состояние объекта.

Данный раздел уже перегружен материалом, но прежде чем перейти к следую­щей теме, я хочу затронуть еще один вопрос. Посмотрите на эти две строки из кон­структора MyTypes:

MyLong = 9223372036854775807L; // В конце литералов должна быть буква 1 или L

InyFloat = 1.0f; // В конце литералов должна быть буква £ или F

Обратите внимание, что в конце числа, присваиваемого myLong, приписана бук­ва L. Хотя в этом нет необходимости, обычно при присваивании литерала перемен­ной типа long это стоит делать. Аналогично обстоит дело и с числами с плавающей точкой. При присваивании переменной с плавающей точкой полезно, а зачастую и необходимо, приписывать в конец числа букву f. В частности, приписав к числу с плавающей точкой f или F, вы можете избавиться от ошибки времени компиляции типа "Потеря точности".

В двух обсуждаемых строках кода можно было бы написать по аналогии с други­ми примерами в конструкторе:

MyLong = Long. MAX VALUE; myFloat = Float. MAX_VALUE;

Я не сделал это просто для того, чтобы показать, что к литералам, присваивае­мым переменным этих типов, часто нужно приписывать 1 или f.

На этом тема инициализации типов исчерпывается. В нескольких следующих разделах я расскажу еще немного о простых типах Java, после чего мы перейдем к обсуждению программы, которая демонстрирует работу с типами.

⅛ UI We г i * — 6 ⅛ г с JiwjJiav ð C OU г $ V f С д Пм у Тур »t∕i г с К a⅛πτ<iy pes ∕feo ∕M√Γ>

File Edit Search View Project Run Tesm Wizards JRefactoiy Tools Window Help

D й — ftIB & *∙’∙∙ C. ⅛fc B >■ 4 M ∣prinTlnf, pause* 3 ¼ ‰ TL ∣ ,sS ‘

)svauno ** ____________ J

L^^~⅛ecodc (String)

. ~’. ………… by5

# Iodcvxuje

Byte

#MHI_V1LUE

Byte;

PareeByte(StElngj)

Byte ⅛

ParβeByte (String, int)

Byte

ToStr lag (byte)

St-Eing

, Тук

Class

♦ vaɪueθf (String)

Byte

Valweθf(StEing, int)

Byte

∙*j<ppublic suing qethinbytejlssteingo (
retwr* byte ■ usteing (byte.hih-v⅛lue) ;
jpublic loι*j g^thylcng(j
⅛⅜⅛e⅛ja⅞i"" ’ ⅝ -χ
bourte loeslfln ) eean * utft,j6w∣ l⅜⅜wyΓ
si∙n t⅛J Э» « [.<

Ft 3β⅛ ®c…∙ SF CaIIMTTypesJpr j;

рис. 9.1. ide-cpe∂a jbuilder поддерживает средство codeinsight. здесь во всплывающем окне показаны поля и методы класса byteI ≠, 3⅛ «Project Source» i ∙⅛ Hl Callmytypes 1S Ш Callmytypes foo

T

Application! java CaIlMyTypeshtml — l, s FraroelJava

Ж -⅛ Imports j

Э « MyTypes

* MyTypesO

J * SetMlnByteAsStrt

* BetMinDoubIeAs

F * BetMInFIoatAsSti.
V BetMinlnteflerAsi

I ∙ V BetMInLonflAsSti j V BelMInShortAsSt

* BetMyByteO

* BetMyDoubIeO J—£t£

Логический тип данных

Я инициализировал переменную типа Boolean (логический) значением true (истина).

MyBool = true

Можно было бы установить ее равной False (ложь). Других значений, которые можно присвоить логической переменной, просто не существует.

В С/С++ и Object Pascal логическую переменную можно трактовать как числовое значение. Однако в Java это не проходит. Все, что можно сделать с логической пере­менной — это присвоить ей True Или False.

В Java целое значение нельзя привести к логическому типу. В Pascal или C++ можно провести параллели между числом ноль и значением False И любым другим скалярным числом и значением True. В Java это невозможно, можно лишь написать код наподобие следующего:

Void JMenuItem2_actionPerformed(ActionEvent Е)

{

Int Num = Integer. parselnt(jTextFieldl. getText () ) ; Boolean myBool = (Num == О? False: true) ; if (myBool ≈ false)

JTextFieldl. setText("false");

Else

JTextFieldl. setText("true");

}

Данный код проверяет, равно ли нулю скалярное число. Если равно, то в myBool заносится false, а если не равно, то в myBool заносится значение true. Это длин­ный обходной путь, но конечный эффект тот же самый, что и при приведении числа к логическому типу. Оператор if, примененный здесь, более детально обсуждается в главе 10.

Символьный тип даных

Значения типа char (символ) — это символьные значения, т. е. буквы наподобие, a,, ,b, или, B’. В них также можно занести базовые синтаксические элементы строк, такие как пробел, символ табуляции или восклицательный знак. Символам можно присвоить и цифры наподобие, l, или,2′. Но нужно четко представлять себе, что символ ∙l, — это совсем не то же самое, что число 1. Символы всегда по­мещаются в одиночные кавычки, а строки — в двойные. Это символ: ∙ а,, а это стро­ка: "Моя строха".

Я инициализирую символьные значения буквой а. В Java обычно применяются строки, а не символы. Если вам нужно работать со строками, необходимо использо­вать класс string, а иногда — класс StringBuffer. Другими словами, в Java нет про­стого типа для хранения строк. Как будет показано в одной из следующих глав, можно создать массив символов, но его нельзя использовать вместо строки. Работа с массивом символов как со строкой в Java слишком сложна. В этом языке такая воз­можность не предусмотрена.

Над символами можно выполнять арифметические операции. Взгляните на сле­дующий код:

Void AddCharMenu_actiOnPerformed(ActionEvent Е)

{

Char temp = ,A,;

String S;

JTextFieldl. setText(""); for (int i = O; i < 26; i++)

{

S = jTextFieIdl. getText();

S = S + temp + ‘ , ; jTextFieldl.βetText(S); temp++;

}

}

Как видите, этот метод предназначен для обработки событий. В частности, он будет вызываться при выборе пункта меню, но его можно было бы применить и для отклика на щелчок на кнопке. (Далее в этой главе будет показано, как организовать меню; пока же сосредоточьтесь на основном коде в теле метода.)

В рассматриваемом коде объявлено две переменных, одна типа char, а другая — string. Символьная переменная инициализирована буквой а, а строка никак не инициализирована. На фрейме данного приложения расположен элемент JTextFieid. Первое, что выполняется в методе после объявления переменных — это очистка текста в элементе JTextFieid.

Затем начинается цикл. Большинство пользователей, видимо, знают, что такое цикл, но не беспокойтесь, если вы с ними не знакомы. О циклах будет подробно рассказано в главе 11. Пока вам достаточно знать, что код между началом цикла и закрывающей его фигурной скобкой повторяется 26 раз. А именно, 26 раз будет по­вторен следующий код:

S = jTextFieldl. getText();

S = S + temp + ’ , ; jTextFieldl. setText(S); temp++;

Сначала строка выбирается из элемента JTextField. При первом выполнении цикла строка будет пустой. Затем к ней добавляется текущее значение temp плюс символ пробела. После первого выполнения цикла результат будет выглядеть так:

А

Значение строки отображается пользователю с помощью вызова метода setτeχt объекта JTextFieid. (Не забывайте, что программисты, пишущие на Java, начина­ют имя JTextFieid с большой буквы J, когда речь идет о классе JTextFieid, но jTeχtField с маленькой буквы j, когда создается имя переменной-экземпляра это­го объекта. Конечно, переменную можно назвать как угодно, но по умолчанию IDE присваивает первому экземпляру объекта этого типа, когда он размещается на фор­ме, имя JrJextFieldl. Второй экземпляр получит имя jTeχtField2 и т. д.)

Последняя строка кода цикла увеличивает на 1 значение переменной temp с по­мощью операции ++. Другими словами, к значению temp, равному, ai, прибавляет­ся 1. Вы можете спросить: "А что значит а плюс 1?" Математики уже наверняка по­няли, каков ответ, но люди с гуманитарным стилем мышления, возможно, удивля­ются, о чем это я говорю, а — это буква, а как можно сложить букву и число? Ну, так уж получается, что а + 1 = В, Что, вообще говоря, естественно.

Вы можете спросить: "Как такое может быть?" Хороший вопрос. При работе с компьютерами необходимо помнить, что в основе всего, что мы видим на экране, находятся числа. Где-то внутри буква а закодирована некоторым числом. Буква В За­кодирована числом, следующим за этим, потом буква C и т. д. Поэтому если к а при­бавить 1, получится следующий элемент этой последовательности, который равен В. Компьютеры обычно очень логичны. (С интуицией у них слабовато, но логику они понимают!) Если буква а представлена числом 65, то числу 66 Соответствует буква В, Числу 67 — буква С И т. д. Поэтому первые две строки рассматриваемого метода мог­ли бы выглядеть так:

Char Temp ≈ 65; // То же, что и Temp = 1A1;

String S;

При работе с символами между операторами char Temp = ,a, ; и char Temp = 65; разницы нет. Может быть, это выглядит странно, но так работают компьютеры.

Рассмотрим следующие две строки из 22-го сонета Шекспира (в переводе А. М. Финкеля):

Не верю зеркалам, что я старик,

Пока ты сверстник с юностью живою.

Люди с гуманитарным мировоззрением понимают приведенное: Шекспир хотел сказать, что он не чувствует себя старым, пока молодо выглядит его любимая. Эта идея естественным образом объясняет многие странности в поведении мужчин зре­лого возраста. Шекспир не выражает свои мысли напрямую, поскольку он хочет:

■ Создать нечто эстетически привлекательное.

■ Выразиться загадочно, чтобы эту загадку было интересно разгадать.

■ Сделать свои слова более весомыми и таким образом привлечь читателя к са­мому плодотворному из всех человеческих видов искусств: созерцанию.

Художники ведут себя по-своему, а компьютеры — по-своему. Любая человечес­кая деятельность имеет свои загадки, свое очарование и свои причины поступать так, а не иначе. Символы в Java тесно связаны с числами. Так принято в мире про­граммистов.

Теперь можно объяснить мысль, выраженную в начале этого раздела. Я сказал, что символ ‘ 1, — это не то же самое, что и число 1. Дело здесь в том, что в компью­терах почти всегда символ,1, представлен числом 49, ‘2’ — числом 50 и т. д. Я ска­зал "почти", т. к. значение символа немного зависит от используемого набора сим­волов. Я еще вернусь к этому вопросу в конце раздела. Ясно, что символ ‘ 1’ весьма отличается от числа 1, и вряд ли здесь нужны дополнительные пояснения

Пора уже вернуться к нашим бара­нам, т. е. к увеличению значения сим­вола с помощью операции ++. Как вы помните, цикл в методе должен вы­полниться 26 раз. Поэтому сейчас код перескакивает опять в начало цикла и с помощью метода getτeχt класса JTextField выбирает текущее значе­ние текстовой строки. Затем к этому значению добавляется текущее значе­ние переменной temp плюс один про­бел:

S = jTextFieldl. getText();

S = S + Temp + , ,;

рис. 9.2. javaynum алфавит с помощью цикла и взаимосвязи между символами и числамиСначала, после выборки из JTextFieid, строка равна ". После выполнения второй строки тела цикла она становится равной "А в ". Затем значение Temp Опять увеличивается с помощью temp++, и становится равным 67, т. е. ’С.

Теперь понятно, что будет после того, как цикл выполнится 26 раз. После его за­вершения этот маленький метод "обучит" Java алфавиту, как показано на рис 9.2.

Я Уже упоминал, что символ, l, обычно равен 49. Слово "обычно" употреблено потому, что одни и те же значения символов, напечатанные разными шрифтами, могут существенно отличаться. Вы знаете, что есть

Шрифты Times New Roman, Courier, Arial, и есть шрифты с готическими или рукописными буквами.

рис. 9.3. одни и те же четыре символа, отображаемые с помощью различных наборов символов обратите внимание, что в третьем наборе символов букв вообще нетПочти все эти шрифты придерживаются соглашения, что символ с кодом 65 выглядит как буква а, символ с кодом 49 Как цифра 1 и т. д. Но ничто не мешает ав­тору какого-либо шрифта поступить логично и поста­вить в соответствие первому символу цифру 1, второму — цифру 2 и т. д. (Вообще-то в этом случае первому символу должна соответствовать цифра 0, поскольку в компьютерах нумерация начинается с нуля. Здесь и далее подразумевается, что л-й символ — это символ с кодом П — прим, перев.) На практике так не делается, иначе это повергло бы компьютерный мир в хаос. Та­кой шрифт не будет работать ни в каком стандартном редакторе. Но нет никакой теоретической причины, запрещающей создание шрифта подобного рода. Бо­лее того, некоторые наборы символов вообще не име­ют цифр и букв. Например, шрифт Wingdings, по умолчанию присутствующий во всех инсталляциях Windows, состоит лишь из маленьких картинок, и сре­ди них нет ни одной буквы или цифры. Пример этого шрифта показан на рис. 9.3, в третьей строке. Подоб-

Ные наборы символов достаточно распространены, и их вполне можно использо­вать, если понимать, что они не предназначены для отображения букв алфавита.

В большинстве наборов символов десятый символ является символом перевода строки, который можно записать так: ,,∖n". В следующей таблице показано, что

Значат другие подобные символы:

Название

Символ

Число

,∖b∙

8

Забой (возврат на 1 символ)

,∖t,

9

Табуляция

,∖n’

10

Перевод строки

,∖f’

12

Конец листа

,∖r∙

13

Возврат каретки

Lξ* I

34

Двойная кавычка

39

Одиночная кавычка

∙∖∖∙

92

Обратная косая черта (обратный слэш)

Вот и все, что я хотел рассказать о символах. Позже мы еще поговорим о масси­вах символов, но это уже совсем другая история.

Работа с байтами

Байты предназначены для представления целых чисел от -128 до 127. Они зани­мают 8 битов.

Почему значения байтов лежат в диапазоне от —128 до 127? А почему не от —250 до 250? А зачем вообще нужен какой-то диапазон?

Дело здесь в том, что в 8 битах можно хранить числа только определенного раз­мера. Бит — это двоичная цифра, которая может содержать только 0 или 1. Число из двух битов позволяет досчитать уже до трех.

Двоичное Десятичное

00 0

01 1

10 2

II 3

Три бита дают возможность считать до 7:

Двоичное Десятичное

000 0

001 1

010 2

011 3

100 4

101 5

ПО 6

III 7

Четыре бита отодвигают верхнюю границу до 15, пять — до 31, шесть — до 63, семь — до 127 и восемь — до 255.

Это все понятно. Непонятно другое: если 8 битов позволяют досчитать до 255, то почему тип byte, занимающий 8 битов, имеет верхнюю границу лишь 127? Дело в том, что восьмой, самый старший, бит содержит знак числа. Если он равен 1, то число отрицательно, а если 0, то положительно. Это значит, что восьмой бит уже за­нят, а максимальное число, которое можно выразить с помощью семи битов, равно 127.

Работа с числами типов Short, int и long

В конце предыдущего раздела разговор шел о битах. Одним из интересных след­ствий рассказанного о битах является то, что следующий код ошибочен:

Byte а = 1, Ь = 2, С; с = А + Ь;

Вместо этого следует писать:

Byte а = 1, Ь = 2, с; с = (byte) (а + Ь) ;

Действие, выполняемое во втором случае, является приведением значения + Ь) к типу byte. Это приведение необходимо, поскольку значение А + Ь может оказаться больше 127. Поэтому компилятор предполагает, что результат сложения не войдет в байт и ожидает тип, больший, чем байт. В данном случае, согласно пра­вилам Повышения типа (type promotion) языка Java, компилятор преобразует тип ре­зультата в int. Единственным способом уговорить его не делать этого является яв­ное приведение типа.

В предыдущем примере если А Равно 100, и Ь равно 100, то А + Ь будет равно 200, что не умещается в семь битов. Поэтому результат сложения будет не 200, а — 56. Число -56 Появилось здесь не случайно, и, возможно, многие из вас уже поняли, в чем тут дело, но для наших целей проще сказать, что результат такого сложения не определен.

Основное правило в данном случае таково: если вы хотите присвоить больший тип меньшему, то необходимо приведение типа. Приведение вынуждает компьютер выполнить что-либо, что он считает нелогичным. И вот вы говорите: "Эй, я знаю, что сложение двух байтов может усложнить мне жизнь, но в данном случае я обе­щаю, что все будет в порядке". Обратите внимание, что приведение типов необхо­димо даже тогда, когда переменным А И ь явно присвоены значения, дающие сумму меньше 127. Компьютер слишком занят другими делами, и он не может проверить, пройдет ли сложение успешно. Вместо этого всю ответственность за код он возлага­ет на вас.

Вот еще один способ пояснить то же самое. Вы можете присвоить меньшее чис­ловое значение большей переменной. Например, вы можете присвоить байт пере­менной типа short:

Byte MyByte = 3; short MyShort;

MyShort = MyByte;

Но в обратную сторону потребуется явное приведение:

Byte MyByte = 3; short MyShort;

MyByte » (byte)MyShort;

Следующий код верен:

Byte A ≈ 100, b = 100; int с; С = А + Ь;

Даже если присвоить переменным А И b значение Byte. MAX_VALUE, значение их суммы не превысит integer. max_value. Поэтому приведение типа не нужно. Дру­гими словами, при присваивании меньшего типа большему можно обойтись обыч­ным кодом.

Символ можно присвоить переменной типа short, int или long, если приме­нить приведение типа:

Short Х; Char у = ,A’ ; Х = (short) (у) ;

В данном случае переменная Х Получит, естественно, значение 65.

Так что же использовать: Byte, short, int или long?

К даньʊму моменту вы уже знаете более чем хотелось бы, о типах byte, int, short и long. Я только не ответил на, быть может, самый главный для вас вопрос: "Какой же тип использовать по умолчанию в моем коде?" К счастью, ответ на этот вопрос очень прост: пользуйтесь типом int!

В наше время большинство компьютеров работают на 32-разрядных процессорах под управлением 32-разрядных операционных систем. И Windows 2000, и Windows 98 являются 32-разрядными операционными системами. Это значит, что они наи­более приспособлены к работе с 32-разрядными значениями. В результате компью­тер чаще тратит больше времени на работу с типом byte, чем с типом int. Нам лег­че работать с числами в диапазоне от —128 до 127, нежели с числами в диапазоне от —2 147 483 648 до 2 147 483 647. Но у компьютеров есть свои предпочтения. Им нисколько не легче работать с числом 1, чем с числом 2 147 483 647. Они для них одинаковы, т. к. оба эти числа аккуратно вписываются в 32 разряда.

Более того, компьютеру непривычно работать со значением, явно приведенным к типу с менее чем 32 разрядами. 32-разрядному процессору Intel труднее обрабаты­вать числа типа byte, чем int! Не обязательно значительно труднее, а иногда и вов­се не труднее, но уж наверняка процессору не легче и не быстрее обрабатывать 8- разрядные значения, чем 32-разрядные.

Зная все это, зачем нам думать о байтах и коротких целых числах? Да, иногда они оказываются полезными. Иногда при обработке отдельных битов действительно бывает важно, сколько разрядов содержит некоторое значение. Или же, если нужно объявить массив из 10 000 целых чисел, то массив из 10 000 чисел типа byte займет 10 000 байтов памяти, а массив из 10 000 чисел типа int займет 40 000 байтов. Но в большинстве случаев эти вопросы несущественны, и можно просто использовать тип int.

К сожалению, в силу этого большинство программистов начального и среднего уровня не получают никакого выигрыша, пытаясь оптимизировать свой код. По­пытки сэкономить память или ускорить выполнение программы с помощью ис­пользования типа byte вместо типа int совсем не обязательно увенчаются успехом, если вы не эксперт в программировании. Более того, эксперты как раз написали ис­пользуемые вами компиляторы и JDK, уже вставив туда оптимизацию, улучшаю­щую ваш код. Другими словами, они знают, когда стоит автоматически преобразо­вывать int в byte или наоборот, и они автоматически и незаметно выполняют за вас эти рутинные действия наиболее безопасным и эффективным образом.

Все это не значит, что опытные программисты не могут эффективно оптимизи­ровать свой код. Но это задача гораздо более сложная, чем представляет себе боль­шинство программистов. Поэтому большая часть наших усилий по оптимизации кода пропадет зря.

Работа с числами типов Float и double

Так же как типы byte, short, int и long все считаются целыми, типы float и double являются типами с плавающей точкой. Выражение "с плавающей точкой" предназначено для обозначения всех чисел, содержащих десятичную точку.

Литерал с плавающей точкой считается значением типа double. Другими слова­ми, если вы напишете 5.5 или 0.2, компилятор автоматически преобразует это число в double. Поэтому такая запись ошибочна:

Float а = 5.6;

Здесь тип double присваивается переменной типа float, что недопустимо, т. к. нельзя присваивать больший тип меньшему. Поэтому необходимо писать так

Float а = (float)(5.6) или так

Float а — 5.6f

Или же так

Float а = 5.6F

Во всех этих операторах по-разному выражено одно и то же, т. е. приписывание к числу с плавающей точкой буквы f или F эквивалентно приведению к типу float.

А вот так можно присвоить значение типа float переменной типа int:

Float а = (float)(1.2) ; int Ь = (int)(а);

Как видите, достаточно простого приведения типа.

Если перемножить числа типов int и double, то по правилам Java результат бу­дет иметь тип double, если только вы явно не приведете его к другому типу. Как уже упоминалось, это называется повышением типа. При сложении или умножении двух чисел типа byte или short тип результата автоматически повышается до int. При сложении или умножении целого числа и числа с плавающей точкой результат всегда будет иметь тип double, если вы не укажете компилятору привести тип к ка­кому-нибудь другому.

Программа для тестирования класса MyTypes

Теперь, наконец, пора применить простые, или примитивные, типы в Java-про­грамме. Программа, приведенная в качестве примера в листинге 9.2, не имеет боль­шой практической ценности, но я надеюсь, что с ее помощью вы лучше поймете простые типы и операции, которые обычно выполняются над ними.

Код в листинге 9.2 демонстрирует применение класса MyTypes. Как и в предыду­щей главе, предполагается, что наряду со своим проектом вы создали каталог Foo И поместили в него класс MyTypes. В Своем текущем проекте вам нужно добавить опе­ратор импорта пакета Foo. Но можно поместить файл MyTypes. java В тот же ката­лог, что и Framel. java, И затем изменить имя пакета на пакет, содержащий ваш проект.

Листинг 9.2. Исходный код файла Frameljava Из проекта CaIIMyTypes, Который входит в состав сопровождающих книгу материалов

Package calImytypes;

Import java. awt.*;

Import java. awt. event.*;

Import j avax. swing.*;

Import Callmytypes. foo. MyTypes;

Public class Framel extends JFrame

{

JPanel ContentPane;

JMenuBar jMenuBarl = new JMenuBarO;

JMenu jMenul = new JMenu () ;

JMenuItem jMenuIteml ≈ new JMenuItem () ;

JMenu jMonu2 ≈ new JMenu () ;

JMenu jMenu3 = new JMenu () ;

JMenuItem rawMyIntegerMenu = new JMenuItemO!

JMenuItem rawMyByteMenu = new JMenuItem () ;

JMenuItem rawMyLongMenu = new JMenuItem () ;

JMenuItem rawMyFloatMenu = new JMenuI tern () ;

JMenuItem rawMyDoubleMenu = new JMenuItem () ;

JMenu jMenu4 = new JMenu () ;

JMenuItem StringMyByteMenu = new JMenuItemO;

JMenuItem StringMyShortMenu = new JMenuItemO!

JMenuItem StringMyIntegerMenu = new JMenuItem() ;

JMenuItem StringMyLongMenu = new JMenuItemO :

JMenuItem StringMyFloatMenu = new JMenuItemO ;

JMenuItem StringMyDoubleMenu = new JMenuItemO;

MyTypes myTypes = new MyTypes () ;

JComboBox jComboBoxl = new JComboBox();

JComboBox jComboBox2 = new JComboBoxO ;

JLabel jLabe11 = new JLabel();

JLabel jLabel2 = new JLabel () ;

JMenuItem allRawMenu = new JMenuItem() ;

JMenuItem AllStringMenu = new JMenuItem() ;

JMenuItem rawMyShortMenu = new JMenuItem();

JTextField jTextFieldl = new JTextFieldO ;

JMenu jMenu5 = new JMenu() ;

JMenuItem AddCharMenu = new JMenuItem() ;

JMenuItem jMenuItem2 = new JMenuItern() ;

// Создание фрейма

Public Framel()

<

EnableEvents(AWTEvent. WINDOWaEVENTaMASK); Try {

Jbɪnit() ;

>

Catch(Exception e)

{

E. printStackTrace();

}

)

∕∕ Инициализация компонентов

Private void jbɪnit() throws Exception

{

ContentPane = (JPanel) this. getContentPane();

ContentPane. SetLayout(null);

This. setSize(new Dimension(400, 300));

This. setTitle("Заголовок фрейма");

JMenul. setText("Файл");

JMenuIteml. setText("Выход");

JMenu2.setText("Опции");

JMenu3.setText("Неформат.");

RawMylntegerMenu. setText("myInteger”);

RawMylntegerMenu. addActionListener(

New Framel_rawMyIntegerMenu_actionAdapter(this)); rawMyByteMenu. setText("myByte"); rawMyByteMenu. SddActionListener(

New Framel_rawMyByteMenu_actionAdapter(this)); rawMyLongMenu. setText("myLong"); rawMyLongMenu. addActionListener(

New Framel_rawMyLongMenu_actionAdapter(this)); rawMyFloatMenu. setText("myFloat");

XawMyFloatMenu. addActionListener(

New Framel_rawMyFloatMenu_actionAdapter(this)) ; rawMyDoubleMenu. setText("myDouble"); rawMyDoubleMenu. addActionListener(

New Framel_rawMyDoubleMenu_actionAdapter(thi s)); jMenu4.setText("AsString");

StringMyByteMenu. setText("myByte");

StringMyByteMenu. addActionListener(

New FramelaStringMyByteMenuaSCtionAdapter(this)); StringMyShortMenu. setText("myShort"); StringMyShortMenu. addActionListener(

New FramelaStringMyShortMenuaSCtionAdapter(this)); StringMyIntegerMenu. setText("mylnteger"); StringMyIntegerMenu. addActionListener(

New FramelaStringMyIntegerMenu__actionAdapter (this)) ; StringMyLongMenu. setText("myLong");

StringMyLongMenu. addActionListener(

New FramelaStringMyLongMenuaSctionAdapter(this)); StringMyFloatMenu. setText("myFloat"); StringMyFloatMenu. addActionListener(

New Framel_stringMyFloatMenu_actionAdapter(this));

StringMyDoubleMenu. setText("myDouble");

StringMyDoubleMenu. SddActionListener( new Framel_stringMyDoubleMenu_actionAdapter(this));

JComboBoxl. setBounds(new Rectangle(33, 50, 331, 27) ) ; jComboBox2.setBounds(new Rectangle(33, 114, 330, 27)) ; jLabell. setText("HeФормат. Макс. Значения");

JLabe11.setBounds(new Rectangle(34, 27, 188, 18)) ; jLabel2.setText("Формат. Макс. Значения"); JLabel2.setBounds(new Rectangle(35, 91, 178, 18)) ; alIRawMenu. setText("Все неформат.");

SllRawMenu. SddActionListener(

New Framel-SllRawMenU-SctionAdapter (this)) ; AllStringMenu. setText("Все формат.");

AllStringMenu. addActionListener(

New Framel-AllStringMenU-SCtionAdapter(this)); rawMyShortMenu. setText("myShort"); rawMyShortMenu. SddActionListener(

New Framel-rawMyShortMenU—actionAdapter(this)); jTextFieldl. setTextCjTextFieldl");

JTextFieldl. setBounds(new Rectangle(33, 174, 329, 22)); jMenu5.setText("Начать");

AddCharMenu. setText("Добавить символ");

AddCharMenu. addActionListener(

New Freunel-AddCharMenU-SctionAdapter(this)); jMenuItem2.setText("Тест логических"); jMenuItem2.addActionListener(

New Framel-jMenuItem2-actionAdapter (this) ) ; jMenuBar1.add(jMenul); jMenuBarl. add(jMenu2); jMenuBarl. add(jMenu5); jMenul. add(jMenuIteml); jMenu2.add(jMenu3); jMβnu2.add(jMenu4); jMenu3.add(rawMyByteMenu); jMenu3.add(rawMyShortMenu); jMenu3.add(rawMylntegerMenu); jMenu3.add(rawMyLongMenu); jMenu3.add(rawMyFloatMenu); jMenu3.add(rawMyDoubleMenu); jMenu3.add(allRawMenu); jMenu4.add (StringMyByteMenu); jMenu4.Bdd(StringMyShortMenu); jMenu4.Sdd(StringMyIntegerMenu); jMenu4.add(StringMyLongMenu); jMenu4.add(StringMyFloatMenu); jMenu4.add (StringMyDoubleMenu); jMenu4.add (AllStringMenu);

ContentPane. add(jLabell, null);

ContentPane. add(j ComboBoxl, null);

ContentPane. add(j Label2, null);

ContentPane. add(jComboBox2, null);

ContentPane. add(jTextFieldl, null); jMenu5.add (AddCharMenu); jMenu5.add(jMenuItem2); this. setJMenuBar(jMenuBarl);

If Перекрыт, чтобы можно было выйти при закрытии окна Protected void ProcessWindowEvent (WindowEvent Е)

{

Super. processWindowEvent(е);

If (e. getID() == WindowEvent. WINDOW_CLOSING)

System. exit(O);

}

}

Void rawMyIntegerMenu_actionPerforɪned (ActionEvent e)

{

JComboBoxl. addɪtern (,,Integer: "+Integer. toString (myTypes. getMylnt ()));

}

Void rawMyLongMenu_actionPerformed(ActionEvent e)

{

JComboBoxl. addltem ("Long : » + Long. toString (myTypes. getMyLong ())) ;

}

Void rawMyFloatMenu_actionPerformed(ActionEvent e)

{

JComboBox 1. addltem ("Float: ,, + Float. toString (myTypes. getMyFloat ())) ;

}

Void rawMyByteMenu_actionPerfoπned(ActionEvent e)

{

JComboBoxl. addltem(nByte: " + Byte. toString(myTypes. getMyByte()));

}

Void rawMyShortMenu_actionPerformed(ActionEvent e)

<

JComboBoxl. addltem ("Short: " + Short. toString (otyTypes. getMyShort ()));

}

Void rawMyDoubleMenu_actionPerformed(ActionEvent e)

{

JComboBoxl. addltem ("Double: "+Double. toString (myTypes. getMyDouble ())) ;

}

Void strIngMyByteMenu_actionPerformed(ActionEvent e)

{

JComboBox2.addltem("Byte: " + myTypes. getMinByteAsString());

}

Void stringMyShortMenu_actionPerformed(ActionEvent e)

{

JComboBox2.addltem("Short: " + myTypes. getMinShortAsString());

}

Void stringMyIntegerMenu_actionPerformed(ActionEvent e)

{

JComboBox2.addltem("Integer: " + myTypes. getMinIntegerAsString());

}

Void StringMyLongMenU-actionPerformed(ActionEvent e)

{

JComboBox2.addltem("Long: " + myTypes. getMinLongAsString());

}

Void StringMyFloatMenU-actionPerformed(ActionEvent e)

{

JComboBox2.addltem("Float: ,* + myTypes. getMinFloatAsString()) ;

}

Void StringMyDoubleMenU-actionPerformed(ActionEvent e)

{

JComboBox2.addltem("Double: " + myTypes. getMinDoubleAsString()) ;

Void AllStringMenusBCtionPerformed(ActionEvent Е)

{

Thia. StringMyByteMenu_actionPerformed(null);

StringMyshortMenusBctionPerformed(null); StringMyIntegerMenusBCtionPerformed(null); StringMyLongMenusBctionPerformed(null); StringMyFloBtMenusBctionPerformed(null); StringMyDoisbleMenusBctionPerformed (null) ;

}

Void allRawMenu_actionPerformed(ActionEvent e)

{

RawMyByteMenusactionPerformed(null); rawMyShortMenusBCtionPerformed(null); rawMyIntegerMenusBCtionPerformed(null); rawMyLongMenusSCtionPerformed(null); rawMyDoubleMenusactionPerformed(null); rawMyFloatMenu_actionPerformed(null);

}

Void AddCharMenusBctionPerformed (ActionEvent e)

{

Char temp =65;

String S;

JTextFieldl. setText (",,) ;
for (int i = O; i < 26; i++)

{

S = jTextFieldl. getText();

S = S + temp + , ;

JTextFieldl. setText(S); temp++;

}

}

Void jMenuItem2sactionPerformed(ActionEvent e)

{

Int Num = Integer. parselnt(jTextFieldl. getText()); boolean myBool = (Num == 25 ? true:false) ; if (myBool == false)

JTextFieldl. setText("false”); else

JTextFieldl. setText("true");

}

}

Class Framel_rawMyIntegerMenu_actionAdapter implements java. awt. event. ActionListener {

Framel adaptee;

FramelsrawMyIntegerMenusactionAdapter (Framel adaptee)

{

This. adaptee = adaptee;

}

Public void actionPerformed(ActionEvent e)

adaptee. rawmyintegermenu__actionperformed (e) ;{

Class Framel_rawMyLongMenu_actionAdapter implements java. awt. event. ActionListener {

Framel adaptee;

Framel_rawMyLongMenu_actionAdapter(Framel adaptee)

<

This. adaptee = adaptee;

}

Public void actionPerformed(ActionEvent e)

{

Adaptee. rawMyLongMenu_actionPerformed(e);

}

}

Class Framel_rawMyFloatMenu_actionAdapter implements java. awt. event. ActionListener {

Framel adaptee;

Framel_rawMyFloatMenu_actionAdapter(Framel adaptee)

<

This. adaptee = adaptee;

}

Public void actionPerformed(ActionEvent e)

{

Adaptee. rawMyFloatMenu_actionPerformed(e);

}

}

Class Framel_rawMyByteMenu_actionAdapter implements java. awt. event. ActionListener {

Framel adaptee;

Framel_rawMyByteMenu_actionAdapter(Framel adaptee)

{

This. adaptee = adaptee;

}

Public void actionPerformed(ActionEvent e)

{

Adaptee. rawMyByteMenu_actionPerformed(e);

}

}

Class Framel_rawMyDoubleMenu_actionAdapter implements java. awt. event. ActionListener {

Framel adaptee;

Framel_rawMyDoubleMenu_actionAdapter(Framel adaptee)

{

This. adaptee = adaptee;

}

Public void actionPerformed(ActionEvent e)

{

Г

Class Frarael-StringMyByteMenU-actionAdapter implements java. awt. event. ActionListener <

Framel adaptee;

Framel_stringMyByteMenu_actionAdapter(Framel adaptee)

{

This. adaptee = adaptee;

)

Public void actionPerformed(ActionEvent e)

{

Adaptee. StringMyByteMenU-SCtionPerformed(e);

)

)

Class Framel_stringMyShortMenu_actionAdapter implements java. awt. event. ActionListener {

Framel adaptee;

Framel_StringMyShortMemi-actionAdapter(Framel adaptee)

{

This. adaptee = adaptee;

)

Public void actionPerformed (ActionEvent e)

<

Adaptee. StringMyShortMenU-actionPerformed(e);

)

}

Class Framel_StringMyIntegerMemi-actionAdapter implements java. awt. event. ActionListener {

Framel adaptee;

Framel_StringMyIntegerMemi-actionAdapter(Framel adaptee)

{

This. adaptee = adaptee;

)

Public void actionPerformed(ActionEvent e)

{

Adaptee. stringMyIntegerMenu_actionPerformed(e);

}

)

Class Framel_stringMyLongMenu_actionAdapter implements java. awt. event. ActionListener {

Framel adaptee;

Framel-StringMyLongMenU-SctionAdapter (Framel adaptee)

{

This. adaptee = adaptee;

)

Public void actionPerformed (ActionEvent e)

{

Adaptee. StringMyLongMemi-actionPer-ermr d(e);

Class Framel_strIngMyFloatMenu_actionAdapter implements java. awt. event. ActionListener {

Framel adaptee;

Framel_stringMyFloatMenu_actionAdapter(Framel adaptee)

{

This. adaptee = adaptee;

}

Public void actionPerformed(ActionEvent e)

{

Adaptee. stringMyFloatMenu_actionPerformed(e);

}

}

Class Framel_stringMyDoubleMenu_actionAdapter implements j ava. awt. event. ActionListener {

Framel adaptee;

Framel_stringMyDoubleMenu_actionAdapter(Framel adaptee)

<

This. adaptee = adaptee;

}

Public void actionPerformed(ActionEvent e)

{

Adaptee. stringMyDoubleMenu_actionPerformed(e);

}

}

Class Framel_AllStringMenu_actionAdapter implements j ava. awt. event. ActionListener

< <?

Framel adaptee;

Framel_AllStringMenu_actionAdapter(Framel adaptee)

{

This. adaptee = adaptee;

}

Public void actionPerformed(ActionEvent e)

{

Adaptee. AllStringMenu_actiOnPerformed(e);

}

)

Class Framel_allRawMenu_actionAdapter implements j ava. awt. event. ActionListener {

Framel adaptee;

Framel_allRawMenu_actionAdapter(Ffamel adaptee)

{

This. adaptee = adaptee;

}

Public void actionPerformed(ActionEvent e)

{

Class Framel_rawMyShortMenu_actionAdapter implements java. awt. event. ActionListener {

Framel adaptee;

Framel_rawMyShortMenu_actionAdapter(Framel adaptee)

{

This. adaptee = adaptee;

)

Public void actionPerformed(ActionEvent e)

{

Adaptee. rawMyShortMenu_actionPerformed(e) ;

}

}

Class Framel_AddCharMenu_actionAdapter implements j ava. awt. event. ActionListener {

Framel adaptee;

Framel_AddCharMenu_actionAdapter(Framel adaptee)

{

This. adaptee = adaptee;

}

Public void actionPerformed(ActionEvent e)

{

Adaptee. AddCharMenu_actionPerformed(e);

)

)

Class Framel_jMenuItem2_actionAdapter implements java. awt. event. ActionListener {

Framel adaptee;

Framel_jMenuItem2_actionAdapter (Framel adaptee)

{

This. adaptee = adaptee;

}

Public void actionPerformed(ActionEvent e)

{

Adaptee. jMenuItem2_actionPerformed (e) ;

}

B этой программе огромный объем кода, но в большинстве своем он очень прост Если бы пришлось писать этот код вручную, то вы бы вскоре угорели от такой рабо­ты. Но JBuilder значительно облегчает процесс создания такого рода программ. Де­вяносто восемь процентов приведенного здесь кода автоматически сгенерировано IDE. Все, что нужно сделать вам — вписать тело нескольких методов.

Но прежде чем приступить к описанию кода, я хочу посвятить несколько строк описанию работы с меню.

Работа с меню

Про меню также рассказывается в главе 13, "Еше раз о компоновках и меню". Здесь приведен еще один пример их использования, так вы лишний раз увидите, как они работают.

Проще всего вставить меню в программу, включив ее с самого начала с помощью мастера создания приложения. При выборе пункта меню File ∣ New ∣ Application мас­тер спросит, не хотите ли вы добавить меню в главную форму. При утвердительном ответе в вашей программе автоматически появятся несколько основных элементов меню, которые затем можно изменить так, как вам нужно. Но ведь при создании проекта не всегда помнишь про меню или собираешься его вставлять.

Если необходимо добавить меню в существующую форму, в которой нет меню, обратитесь к странице Swing Containers палитры компонентов и поместите на фор­му элемент JMenuBar. Затем добавьте в конец метода Jbɪnit Следующую строку:

This. SetJMenuBar(menuBar);

Если вы хотите добавить меню в существующий экземпляр JFrame Полностью вручную, то для этого потребуется поместить в программу несколько простых строк. Сначала добавьте следующий код в начало объявления Framel:

Public class Framel extends JFrame

{

JPanel ContentPane;

JMenuBar menuBar = new JMenuBar () ;

JMenu menu = new JMenu () ;

. . . ∕∕ Дальше ход опущен

Здесь включены описания Framei И ContentPane, Чтобы было легче найти место вставки.

Теперь в метод jbinit добавьте следующие строки:

MenuBar. add(menu);

This. SetJMenuBar(menuBar);

Тот факт, что вы можете создавать визуальные элементы либо в коде, либо с по­мощью визуальных инструментов, возможен благодаря технологии, которую компа­ния Borland называет Инструментами двунаправленной разработки (two-ways tools). Рни представляют собой замечательную вещь, т. к. гарантируют, что в вашей работе нет никаких "черных ящиков". При создании программы вы можете пользоваться либо исходным кодом, либо визуальными средствами — как сами захотите. Реально большинство разработчиков использует комбинацию этих двух способов. Но глав­ное, что JBuilder не привязывает вас жестко к какому-либо средству визуальной раз­работки, генерирующему непонятный для вас код. Вместо этого JBuilder использует стандартный Java-код.

Вы сможете редактировать меню в панели структуры для Framel, Как показано на рис. 9.4. Чтобы добраться до этого места, щелкните правой кнопкой на строке Menu в панели структуры и выберите пункт Activate Designer.

Для редактирования пунктов меню можно воспользоваться либо самим конст­руктором, либо инспектором, расположенным справа от конструктора. На рис. 9.4 справа от слова Play виден небольшой пунктирный прямоугольник. Если дважды щелкнуть на нем, он превратится в поле редактирования, в котором можно ввести название нового пункта меню. При добавлении этого названия автоматически со­здается и сам пункт меню. Точно так же можно добавить и элемент JMenuitem В ко­нец существующего выпадающего меню. Например, если дважды щелкнуть на обла-

рис. 9.4.
работа с меню в конструкторе меню. слева вверху
— панель навигации, под ней находится панель структуры.
в середине расположен конструктор меню, а с правой стороны
— инспектор

Сти под словами AsString или All Raw, то можно будет ввести название пункта меню, а в меню добавится элемент JMenuitem.

Для дальнейшего редактирования меню необходимо перейти в инспектор. Поля, с которыми вам пока нужно работать — это свойство text на странице Properties и со­бытие action Performed на странице Events. Переключение между этими страницами осуществляется с помощью закладок в нижней части инспектора, как показано на рисунках 9.5 и 9-6.

На рис. 9.5 видно, что для элемента JMenuItem имя jMenultemX, созданное по умолчанию я поменял на AIIRawMenu. Это сделано потому, что имя AIIRawMenu гово­рит мне о назначении этого пункта, а имя jMenultemX не несет никакой информа­ции.

properties events ,t properties1 events f
... - a - . 
гт : к ~ 
opaque true s~;
preferredslze 59.21 
pressedlcon 
toquestfocusenabied true 
tojioverenabied false 
rolloverlcon 
tolloverseiectedicon 
selectedlcon u
 ⅝⅝j¾hhhmm⅛i 
too∣tiptext 
verityinputwhenfocust... true 
verticaiaiignment __ center^ ';
brticaltextposition center '

 ■ » ... . . ... - . ∙ .⅛
at⅛o∏per⅛rtτted ancestoradded mlrawmenu actionpe<c∙mβa
ancestor⅜loved 
a∩cestorwoved 
a∩cestorremoved 
ancestorresized 
caretpositionchanged 
componentadded 
componenthidden 
componentmoved 
componentremoved 
componentresized _ 
componentshown 
tbcusgained

рис. 9.5. страница properties (свойства) инспектора
рис. 9.6. страница events (события) инспектора

На странице Events, показанной на рис. 9.6, видно, что с этим пунктом меню я связал событие. Для этого я просто перешел на страницу Events, выделил строку actionPerformed и нажал клавишу Enter. IDE автоматически вставил слова AiiRawMenu_actionPerformed, А в программу был помещен следующий код:

// Предшествующий код опущен

Void allRawMenu_actionPerformed(ActionEvent e)

I

)

}

Class Framel_allRawMenu_actionAdapter implements java. awt. event. ActionListener I

Framel adaptee;

Framel_allRawMenu_actionAdapter(Framel adaptee)

{

This, adaptee = adaptee;

}

Public void actionPerformed (ActionEvent e)

{

Adaptee. allRawMenu_actionPerformed(e);

}

I

Вы уже встречались с подобным кодом. Класс в конце данного фрагмента являет­ся адаптером, автоматически обрабатывающим события. В частности, при выборе пользователем пункта AIIRawMenu класс Framel_AllRawMenu_actionAdapter Авто­матически вызовет метод AllRawMenu_actionPerformed. События более подробно рассматриваются в главе 15, "Генерация событий".

В рассматриваемой программе используются вложенные меню, что видно на рис. 9.4. Номенклатура элементов меню такова. Строка меню вверху окна называет­ся JMenuBar. Отдельные пункты этого меню содержатся в экземплярах класса JMenu. Когда вы помещаете на форму элемент JMenu, вы получаете пункты меню типа "He — формат." и "Формат.". Каждый из них является экземпляром класса JMenuitem.

Если спуститься на один уровень ниже, чтобы JMenuitem С именем Raw также со­держал пункты меню, получится вложенное меню. В него входят экземпляры JMenuitem С заголовками myByte, mylnt и т. д. Это вложенное меню создано с помо­щью щелчка правой кнопкой мыши на слове Raw и выбора в возникшем меню пунк­та Insert Nested Menu (Вставка вложенного меню).

Код приложения CaIIMyTypes

В основном методы программы CaiiMyTypes, обрабатывающие выбор пункта меню, очень просты. Они просто вызывают методы класса MyTypes и отображают пользователю полученные результаты.

Вызовы методов демонстрируют использование каждого из числовых типов. (В программе также показано применение логического и символьного типов, но код этих методов был приведен ранее в данной главе в разделах "Символьный тип дан­ных" и "Логический тип данных".)

Вот код для работы с типом int:

Void rswMyIntegerMenusSCtionPerformed(ActionEvent Е)

{

JComboBoxl. addɪtem (" Integer: "+Integer. toString (myTypes. getMylnt () ) ) ;

}

Как показано на рис. 9.2, главная форма для этой программы содержит два выпа­дающих списка JCoxnboBox. Их можно найти на странице Swing палитры компонен­тов. Код в рассматриваемом методе заносит в первый из этих списков некоторый текст. Это выполняется с помощью вызова метода additem класса JComboBox.

В классе MyTypes имеется метод getMylnt, возвращающий значение, которым была инициализирована переменная myint в конструкторе MyTypes:

Mylnt = Integer-MAXsVALUE; // 2147483647;

// Здесь опущена часть хода

Pxιblic int getMylnt ()

{

Return mylnt;

}

Очевидно, что метод getMylnt вернет значение 2147483647. Это число с помо­щью метода toString класса integer преобразуется в строку. После этого програм­ма хранит в памяти строковое значение "2147483647". Затем с помощью операции + я присоединяю к этой строке строку "integer: ", и в результате получается "integer: 2147483647". (Подробнее об операциях будет рассказано в главе 11,

"Циклы, операторы и тип данных Currency".) Это значение и заносится в JCoinboBox.

Еще ОДИН Метод обработки события SCtionPerformed ДЛЯ класса JMenuItem выглядит следующим образом:

1

Void StringMyIntegerMenusSCtionPerformed(ActionEvent Е)

{

JCoxnboBox2. sddltem (" Integer: " + my Types. getMinlntegerAsS tring ()) ;

1

Приведенный здесь код вызывает метод getMinlntegerAsS tring класса MyTypes. Вот как он выглядит:

Public String getMinlntegerAsString()

{

Return Integer. toString(Integer. MIN_VALUE);

}

K этому моменту вы уже должны уловить ритм рассматриваемой программы. Она состоит из последовательности элементов меню, каждый из которых вызывает ме­тод из класса MyTypes. Вызвав все методы этого класса, программа завершается.

Я не буду разбирать все эти методы, поскольку этот повторяющийся процесс до­статочно прост для понимания. Вместо этого я предлагаю вам потратить некоторое время на изучение листинга 9.2, разбирая его, пока он не станет для вас полностью понятен. Кроме того, вам стоит потратить время и на запуск программы из IDE-cpe-

Ды JBuilder, экспериментируя с ней, как вам только заблагорассудится. А лучше все­го было бы, вместо запуска моей копии полностью самостоятельно создать эту про­грамму bIDE.

При работе с этой программой обратите внимание, что в ней показаны стандарт­ные классовые типы языка Java, используемые как оболочки для каждого из прими­тивных типов:

Простой тип Классовый тип

Byte

Byte

Short

Short

Int

Integer

Long

Long

Float

Float

Double

Double

Каждый из классовых типов хотя бы раз был использован в программе. Обычно я просто вызываю метод Tostring Рассматриваемого класса или использую его поля max_value и min_value. Вообще-то в этих классах кроме упомянутых членов почти ничего и нет, но, если вы хотите, вы можете воспользоваться справочной системой или просмотреть исходный код и узнать про эти классы больше.

В приложении CallMyTypes Есть два метода, которые заслуживают чуть большего внимания. Если вы работаете в своей программе с вложенными меню, то потребует­ся значительное время для заполнения списков JConiboBox Результатами из всех ме­тодов класса MyTypes. Например, вы отдельно щелкаете на пунктах myByte, myShort, mylnt и т. д. Хотя этот процесс и не смертелен, он все же может оказаться несколько утомительным. Поэтому я создал пункт меню с названием "Все неформат.", который сам вызывает все вложенные пункты JMenuitem. Вот метод, который вызывается при выборе пункта меню "Все неформат.":

Void allRawMenu_actIonPerformed(ActionEvent Е)

{

RawMyByteMenu_actionPerformed(null); rawMyShortMenu_actionPerformed(null); rawMyIntegerMenu_actionPerformed(null); rawMyLongMenu_actionPerformed(null); rawMyDoubleMenu_actionPerformed(null); rawMyFloatMenu_actionPerformed(null);

)

Данный код вызывает все методы отклика, связанные с вложенными элементами JMenuitem Этой группы. Поэтому один щелчок на пункте меню "Все неформат." имеет тот же эффект, что и вызов всех других методов этой группы элементов меню.

Каждый из методов отклика, вызываемых при обработке этого события, прини­мает в качестве параметра значение типа ActionEvent:

Void stringMyIntegerMenu_actionPerformed(ActionEvent Е)

Тип ActionEvent обсуждается в главах 14 и 15. В нашем случае этот параметр полностью игнорируется, и вместо него можно было бы передать null.

Значение null можно рассматривать как указатель на неинициализированный экземпляр класса. Обычно адрес объекта задается именем переменной, указываю­щей на него:

MyTypes myTypes = new TMyTypes();

Здесь переменная myτypes ссылается на существующий экземпляр класса типа MyTypes. Она является указателем на участок памяти, где расположен инициализи­рованный экземпляр класса MyTypes. Если переменной myτypes присвоить значе­ние null, то в этом случае мы говорим, что эта переменная не указывает на никакой инициализированный экземпляр класса MyTypes. Она не указывает ни на что и не ссылается ни на что. Это просто переменная, и с ней ничего нельзя сделать кроме упоминания ее имени. Ее значение — ничто, пустота!

Объект, который не указывает ни на что, чаще всего бесполезен. Но в нашем слу­чае от него есть кое-какой толк. А именно, с его помощью можно вызывать методы обработки событий, не имея инициализированной переменной типа ActionEvent. Так как вы не собираетесь использовать объект ActionEvent, То в данном случае его можно спокойно опустить.

Резюме

Вот и все, что я хотел вам рассказать о простых, или примитивных, типах языка Java. Я надеюсь, что эта глава дала вам некоторое представление о том, что это та­кое.

Данная глава содержит также в качестве примера приложение CaliMyTypes, в ко­тором показано, как применять эти простые типы. Наверно, не менее важно и то, что в этом приложении интенсивно применяются меню и события. Обычно созда­ние меню и событий в Java требует много времени и ввода большого объема текста. JBuilder устраняет необходимость ввода всех повторяющихся пунктов меню и кода обработчиков событий. Он буквально экономит если не дни, то уж точно часы рабо­чего времени

Создание программы, подобной CaliMyTypes, было бы серьезной работой, если бы не было помощи со стороны визуальных средств, присутствующих в JBuilder. Хотя программа по своей сути очень проста: код программы не трудный, а просто длинный и повторяющийся. JBuilder избавляет нас от всей этой рутинной работы. Уже по этой причине данный инструмент стоит использовать.

Чарли Калверт

Глава 10

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *