Основные структуры языка Java

Страница создана Камила Пугачева
 
ПРОДОЛЖИТЬ ЧТЕНИЕ
Основные
структуры
языка Java
    В этой главе...

• Простая программа на языке Java
Т   Комментарии
• Типы данных
Т   Переменные
• Присваивания и инициализации
•   Операторы
Т Строки
Т   Поток управления
•   Большие числа
Т   Массивы

         считать, что вы успешно инсталлировали средства программирования на языке
Java и можете выполнять простые программы, показанные в главе 2. Настало время созда-
вать собственные программы. В этой главе вы узнаете, как в языке Java реализуются ос-
новные концепции программирования, например, типы данных, ветви и циклы.
    К сожалению, на языке Java нелегко написать программу, использующую графиче-
ский пользовательский интерфейс, — для этого нужно изучить массу деталей, связан-
ных с окнами, полями ввода, кнопками и т.п. Поскольку описание таких технических
56    Глава 3. Основные структуры языка Java

подробностей увело бы нас далеко в сторону от нашей основной цели — анализа ос-
новных структур языка, в этой главе мы рассмотрим лишь "игрушечные" программы,
иллюстрирующие то или иное понятие. Все эти программы просто выводят на кон-
соль результаты своей работы. (В среде Windows консолью является окно MS DOS.)
При вводе данных информация считывается из всплывающего окна. В частности, мы
будем создавать приложения, а не аплеты.
   В заключение заметим, что опытные программисты на языке C/C++ могут просто
бегло просмотреть эту главу, обратив особое внимание на замечания о языке C/C++,
разбросанные по тексту. Программистам на других языках, например Visual Basic,
многие понятия окажутся знакомыми, хотя их синтаксис совершенно другой. Таким
читателям мы советуем тщательно изучить эту главу.

Простая программа на языке Java
   Рассмотрим поближе простейшую программу, какую только можно себе предста-
вить, — она просто выводит сообщение в консольное окно.
public class FirstSample
{
   public static void main(String[] args)
   {
     System.out.println("We will not use 'Hello, World!'");

     Этому примеру стоит посвятить столько времени, сколько потребуется, чтобы
привыкнуть к особенностям языка; эти моменты будут встречаться во всех приложе-
ниях. Первый и главный момент — в языке Java строго различаются прописные и строчные
буквы. Если вы перепутаете их (например, набрав слово Main вместо main), програм-
ма выполняться не будет.
     Теперь просмотрим исходный код построчно. Ключевое слово p u b l i c называется
модификатором доступа (access modifier); такие модификаторы управляют доступом к
данному коду из других частей программы. Более подробно мы рассмотрим этот вопрос
в главе 5. Ключевое слово c l a s s напоминает нам, что все сущности в языке Java нахо-
дятся внутри классов. Классы будут детально рассматриваться в следующей главе, а пока
мы будем считать их некими контейнерами, в которых заключена логика программы,
определяющая работу приложения. Как указывалось в главе 1, классы— это строитель-
ные блоки, из которых состоят все приложения и аплеты, написанные на языке Java. Все
сущности в программах на языке Java должны находиться внутри классов.
     За ключевым словом c l a s s следует имя класса. Правила образования имен классов
не слишком строги. Имя должно начинаться с буквы, а остальная его часть может быть
любой комбинацией букв и цифр. Длина имени практически не ограничена. В качестве
имени класса нельзя использовать зарезервированные слова языка Java (например,
p u b l i c или i f ) . (Список зарезервированных слов приведен в приложении.)
     Как видно по имени F i r s t S a m p l e , классы принято называть именами существи-
тельными, начинающимися с прописной буквы.
     Файл, содержащий исходный текст, должен называться так же, как и открытый
класс, и иметь расширение . Java. Таким образом, класс мы должны записать в файл
F i r s t S a m p l e . j ava. (Как и прежде, прописные и строчные буквы различаются — не
Простая программа на языке Java                                    57

используйте имя f i r s t s a m p l e . Java.) Если вы этого не сделаете, то при попытке
выполнить компиляцию получите замечательное по своей ясности собщение об
ошибке ("Public class FirstSample must be defined in a file called 'FirstSample.java'" —
"Открытый класс FirstSample должен быть определен в файле 'FirstSample.java'").
     Если вы правильно назвали файл и не сделали опечатки в исходном тексте про-
граммы, то, скомпилировав его, получите файл, содержащий байт-коды, соответст-
вующие данному классу. Компилятор языка Java автоматически назовет этот файл
F i r s t S a m p l e . c l a s s и сохранит его в каталоге, где содержится исходный файл. Ос-
талось выполнить байт-коды с помощью интерпретатора языка Java, набрав команду
java FirstSample
(Не забудьте отбросить расширение . c l a s s . ) Выполняясь, программа просто выве-
дет на экран строку "We will not use 'Hello, World!'".

          Аплеты имеют другую структуру — см. главу 10.

   Когда для запуска скомпилированной программы используется команда
java ИмяКласса,
интерпретатор языка Java всегда начинает свою работу с выполнения метода main
указанного класса. Следовательно, чтобы программа вообще могла выполняться, в
классе должен содержаться метод main. Разумеется, в класс можно добавить свои собст-
венные методы и вызывать их с помощью метода main. (Мы покажем, как создавать
такие методы в следующей главе.)

          В соответствии со спецификацией языка Java метод main должен быть объявлен от-
          крытым ( p u b l i c ) . (Спецификация языка Java (Java Language Specification) является
          официальным документом. Его можно просмотреть или загрузить с Web-страницы
          h t t p : / / j a v a . s u n . c o m / d o c s / b o o k s / j l s . ) Однако некоторые версии интерпретато-
          ра языка Java пытались запускать программы, даже когда метод main не имел моди-
          фикатора p u b l i c . Эта ошибка была помещена в список замеченных неполадок, пред-
          ставленный на сайте h t t p : / / d e v e l o p e r . j a v a . s u n . c o m / d e v e l o p e r / b u g P a r a d e ,
          под номером 4252539. Однако она сопровождалась примечанием: "закрыта, исправ-
          лению не подлежит". Разработчики компании Sun выступили с разъяснениями, что
          спецификация виртуальной машины языка Java (Java Virtual Machine Specification) не
          требует, чтобы метод main был открытым (см. Web-страницу h t t p : / / J a v a . s u n . com/
          docs/books/vmspec), а попытка исправить эту ошибку "может вызвать проблемы".
          К счастью, здравый смысл в итоге восторжествовал. Интерпретатор языка Java в паке-
          те SDK 1.4 требует, чтобы метод main был открытым.
                Эта история имеет несколько интересных аспектов. С одной стороны, стано-
          вится как-то неуютно от того, что разработчики, призванные гарантировать высо-
          кое качество программ, часто слишком много работают сверхурочно и не всегда
          проверяют слабые места языка Java, предпочитая отмахиваться от замеченных
          ошибок. С другой стороны, стоит отметить тот факт, что компания Sun размести-
          ла список ошибок и способы их исправления на Web-сайте, открыв его для иссле-
          дования. Этот "парад ошибок" представляет собой весьма полезный ресурс для
          программистов. Вы даже можете "проголосовать" за вашу любимую ошибку.
          Ошибки, набравшие наибольшее число голосов, будут исправлены в следующих
          выпусках пакета SDK.
58      Глава 3. Основные структуры языка Java

    Обратите внимание на фигурные скобки в исходном тексте программы. В языке Java
так же, как и в языке C/C++, фигурные скобки используются для выделения частей про-
граммы (обычно называемых блоками). В языке Java код любого метода должен начинаться
с открывающей фигурной скобки { и завершаться закрывающей фигурной скобкой }.
    Использование фигурных скобок вызвало массу недоразумений и противоречий.
Обычно мы стараемся располагать скобки одну под другой, выравнивая их с помощью
пробелов. В то же время компилятор языка Java игнорирует пробелы, поэтому, в
принципе, фигурные скобки можно ставить где угодно. Изучая различные операторы
цикла, мы поговорим о скобках более подробно.
    Пока мы не будем обращать внимание на ключевые слова s c a t i c void, считая их
просто необходимой частью программы на языке Java. В конце- главы 4 мы полностью
раскроем смысл этих слов. Сейчас важно помнить, что каждое приложение на языке
Java должно иметь метод main, заголовок которого приведен ниже.
public class ИмяКласса
 {
    public static void main(String[] args)
     {
        команды программы

             Вы уже знаете, что такое класс. Классы в языке Java похожи на классы в языке C/C++,
             однако между ними есть несколько различий, которые могут завлечь вас в ловушку.
             Например, в языке Java все функции являются методами какого-либо класса. (В стан-
             дартной терминологии они называются методами, а не функциями-членами.) Следо-
             вательно, в языке Java должен существовать класс, которому принадлежит метод main.
             Вероятно, вы знакомы с концепцией статических функций-членов в языке C++. Это
             функции-члены, определенные внутри класса и не принадлежащие ни одному объекту.
             Метод main в языке Java всегда является статическим. В заключение, как и в языке
             C/C++, ключевое слово v o i d означает, что метод не возвращает никакого значения. В
             отличие от языка C/C++, метод main не передает "код выхода" операционной системе.
             Если метод main завершает свою работу нормально, код выхода программы на языке
             Java равен 0, что свидетельствует о ее успешном выполнении. Чтобы прекратить вы-
             полнение программы с другим кодом выхода, используйте метод System, e x i t .

     Теперь обратите внимание на следующий фрагмент кода:
{
     S y s t e m . o u t . p r i n t l n ( " W e w i l l n o t u s e 'Hello, 1 W o r l d ! ' " ) ;
}
     Фигурные скобки отмечают начало и конец тела метода, состоящего лишь из од-
ного оператора. Как и в большинстве языков программирования, операторы языка
Java можно считать предложениями. В языке Java каждый оператор должен заканчи-
ваться точкой с запятой. В частности, символ конца строки не означает конец опера-
тора, поэтому оператор может занимать столько строк, сколько потребуется.
     Тело метода main состоит из оператора, который выводит на консоль одну строку
текста.
     В данном примере мы используем объект System, out и вызываем его метод
p r i n t l n . Заметьте, что для вызова метода используется точка. В общем случае вызов
метода имеет следующий вид:
объект.метод(параметры)
Комментарии             59

    В нашем примере мы вызываем метод p r i n t l n , передавая ему текстовую строку в
качестве параметра. Метод выводит этот текст на консоль, выполняя переход на сле-
дующую строку. В языке Java, как и в языке C/C++, для разделения строк используются
двойные кавычки. (Далее в этой главе мы рассмотрим работу со строками подробнее.)
    Методы в языке Java, как и функции в любом другом языке программирования, мо-
гут иметь один или несколько параметров, либо не иметь их вовсе (в некоторых язы-
ках они называются аргументами). Даже если метод не имеет параметров, нужно ос-
тавлять пустые скобки. Например, есть вариант метода p r i n t l n без параметров, вы-
водящий на экран пустую строку. Его вызов выглядит так:
System.out.println();

         В объекте S y s t e m , o u t есть метод p r i n t , который не добавляет к строке символ
         перехода на новую строку. Например, оператор S y s t e m . o u t . p r i n t ( " H e l l o " )
         выводит текст " H e l l o " и оставляет курсор в конце строки. Следующий вывод
         появится на экране сразу за буквой "о".

Комментарии
    Комментарии в языке Java, как и в большинстве языков программирования, игно-
рируются при выполнении программы. Таким образом, в программу можно добавлять
столько комментариев, сколько потребуется, не опасаясь увеличить ее объем. В языке
Java есть три способа выделения комментариев в тексте. Чаще всего используются две
косые черты //, при этом комментарий начинается сразу за символами / / и продол-
жается до конца строки.
 System.out.println{"We will not use 'Hello, World!'");
 // Остроумно, не правда ли?
    Если нужны более длинные комментарии, можно каждую строку начинать симво-
лами //. Кроме того, для создания больших блоков комментария можно использовать
разделители /* и * /, как показано в листинге 3.1.

I. * /
2.    Это первый пример программы в главе 3
3.    Copyright (С) 1996...2000 Cay Horstmann and Gary Cornell
4. */
5.
6. public class FirstSample
7. <
8.   public static void main(String[]              args)
9. {
10. System.out.println("Мы не будем говорить 'Hello, World!'");
II. }
12. }

   В заключение отметим, что в языке Java есть и третья разновидность комментари-
ев, которую можно использовать для автоматической генерации документации. Эти
комментарии начинаются символами / * * и заканчиваются символами */. Более под-
робную информацию об этом виде комментариев и автоматической генерации доку-
ментации можно найти в главе 4.
60      Глава 3. Основные структуры языка Java

          Комментарии, выделяемые символами /* и */, в языке Java не могут быть вло-
          женными. Это значит, что фрагмент кода нельзя отключить, просто окружив его
          символами /* и * /, поскольку отключаемый код сам может содержать разделите-
          ли */ и */.

Типы данных
   Язык Java является строго типизированным. Это значит, что тип каждой переменной
должен быть объявлен. В языке Java есть восемь основных типов (primitive types) данных.
Четыре из них относятся к целым числам, два — к действительным числам с плавающей
точкой, один представляет собой символьный тип char, используемый для представле-
ния символов в формате Unicode (см. раздел, посвященный типу char), и последний —
булевский тип b o o l e a n — применяется для логических величин.

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

Целые числа
     Целочисленные типы используются для представления как положительных, так и
отрицательных чисел, не имеющих дробной части. В языке Java есть четыре целочис-
ленных типа. Они представлены в табл. 3.1.
     В большинстве случаев тип i n t наиболее удобен. Если нужно задать количество
жителей нашей планеты, нет никакой необходимости прибегать к типу long. Типы
b y t e и s h o r t в основном используются в специальных приложениях, например, при
низкоуровневой обработке файлов или для хранения больших массивов при недос-
татке памяти.

 Тип        Требуемый объем памяти              Диапазон (включительно)
 int        4 байт                              от -2,147483648 до 2147483647
                                                (больше 2 миллиардов)
 short     2 байт                               от-32768 до 32767
 long      8 байт                               от-9223372036854775808L
                                                до -9223372036854775807L
 byte       1 байт                              от-128 до 127

  В языке Java диапазоны целочисленных типов не зависят от машины, на которой
выполняется программа. Это облегчает страдания программистов, которым необходи-
Типы данных        61

мо переносить программное обеспечение с одной платформы на другую и даже из од-
ной операционной системы — в другую на одной и той же платформе. В противополож-
ность этому, программы на языках С и C++ на каждом процессоре используют тип, ко-
торый является наиболее эффективным именно на нем. В результате программа на
языке С, которая отлично работает на 32-разрядном процессоре, может привести к це-
лочисленному переполнению в 16-разрядной системе. Поскольку программы на языке
Java одинаково работают на любых машинах, диапазоны разных типов фиксированы.
    Длинные целые числа имеют суффикс L (например 4 000000000L). Шестнадцате-
ричные числа имеют префикс Ох (например OxCAFE). Восьмеричные числа имеют
префикс 0. Например, 010 — это число 8. Естественно, это может привести к недора-
зумениям, и мы не рекомендуем применять восьмеричные числа.

             В языках С и C++ ключевое слово i n t означает целочисленный тип, зависящий от
             машины, для которой предназначена программа. На 16-разрядном процессоре,
             например процессоре 8086, целые числа занимают 2 байт. На 32-разрядном про-
             цессоре, например процессоре Sun SPARK, они занимают 4 байт. На процессоре
             Intel Pentium размер целого типа в языках С и C++ зависит от операционной сис-
             темы: в DOS и Windows 3.1 целые числа занимают 2 байт. При использовании 32-
             разрядного режима работы в системе Windows целые числа занимают 4 байт. В
             языке Java размеры всех числовых типов не зависят от платформы, на которой
             выполняется программа.
             Заметим, что в языке Java нет беззнаковых типов u n s i g n e d .

Типы чисел с плавающей точкой
   Эти типы предназначены для представления чисел, имеющих дробную часть. В
языке Java есть два типа для чисел с плавающей точкой, показанные в табл. 3.2.

 Таблица 3.2. Типы для чисел с плавающей точкой
1
    Tun         Требуемый объем памяти Диапазон (включительно)

    float       4 байт                    Приблизительно ±3.40282347E+38F

                                           (6-7 значимых десятичных цифр)

    double      8 байт                    Приблизительно ± 1.7976931348623157E+308F

                                           (15 значимых десятичных цифр)

   Имя double означает, что точность этих чисел вдвое превышает точность чисел
типа f l o a t . (Некоторые называют их числами с двойной точностью.) В большинстве
приложений наиболее удобным является тип double. Ограниченной точности чисел
типа f l o a t во многих случаях просто недостаточно. Семи значимых (десятичных)
цифр, возможно, хватит для того, чтобы точно выразить вашу годовую зарплату в
долларах и центах, однако для зарплаты президента вашей компании этого будет явно
62       Глава 3. Основные структуры языка Java

недостаточно. Единственная причина, по которой тип f l o a t нее еще используется, —
редкие ситуации, в которых важна скорость обработки чисел (у чисел типа f l o a t она
выше). Кроме того, тип f l o a t используется при хранении больших массивов дейст-
вительных чисел.
   Числа типа f l o a t имеют суффикс F, например 3 . 402F. Числа с плавающей точ-
кой, не имеющие суффикса F (например 3.4 02), всегда рассматриваются как числа
типа double. Для их представления можно (но не обязательно) использовать суф-
фикс D, например 3 . 402D.
   Бее вычисления, производящиеся над числами с плавающей точкой, следуют стандарту
IEEE 7 5 4. В частности, в языке Java есть три специальных числа с плавающей точкой:

     •   положительная бесконечность;
     •   отрицательная бесконечность;
     • NaN (не число).

   Они используются для обозначения переполнения и ошибок. Например, результат
деления положительного числа на 0 равен положительной бесконечности. Вычисле-
ние 0/0 или извлечение квадратного корня из отрицательного числа равно NaN.

           В языке Java существуют константы D o u b l e . POSITIVE_INFINITY, Double.
           NEGATIVE_INFINITY и Double .NaN (а также соответствующие константы типа f l o a t ) .
           Однако на практике они редко используются. В частности, для того, чтобы убедиться,
           что некий результат равен константе Double. NaN, нельзя вь полнить проверку
              if (х == Double.NAN) // Тождественно ложное; условие.
           Все величины, "не являющиеся числами", считаются разными. Однако можно вы-
           зывать метод Double.isNaN:
              if (Double.isNaN(x)) // Проверка, является ли х "не числом".

Символьный тип
   Во-первых, для обозначения констант типа char используются одиночные кавычки.
              1
Например, 'Н — это символ. Он отличается от "Н", строки, состоящей из единствен-
ного символа. Во-вторых, тип char обозначает символы, представленные в формате
Unicode. Вы можете не знать этот формат и не беспокоиться о нем, если не разрабаты-
ваете приложения, в которых нужна поддержка языков, помимо английского. Посколь-
ку формат Unicode был разработан для обработки практически всех символов всех
письменных языков, существующих в мире, он является 2-байтсвым кодом. В нем допус-
кается 65536 символов, из которых обычно используется около 35000. Формат Unicode
намного богаче набора ASCII, представляющего собой 1-байтовый код, состоящий из
128 символов, или широко используемого расширения ISO 8859-1, с помощью которого
можно закодировать 256 символов. Этот набор символов (который программисты часто
называют множеством символов "Latin-1") представляет собой подмножество формата
Unicode. Точнее, эти символы являются первыми 256 символ;1ми кодировки Unicode.
Таким образом, код символов ' а ' , ' 1 ' , ' [' и ' а ' в формате Unicode не превышает 256.
Коды символов в формате Unicode лежат в диапазоне от 0 до 65535, однако обычно они
выражаются как шестнадцатеричные величины от '\u0000' до 'uFFFF' (в то время
Типы данных     63

как в формате ISO 8859-1 их диапазон ограничивается числами ' \u0000 ' и ' \uOOFF').
Префикс \и означает, что символ записан в формате Unicode, а следующие за ним че-
тыре шестнадцатеричные цифры задают сам символ. Например, \u2122 — это символ
торговой марки (™). Более подробную информацию о формате Unicode вы можете
найти Haweb-CTpaHHqehttp: //www.unicode.org.
   Кроме префикса \и, означающего символ в формате Unicode, в языке Java есть
еще несколько специальных символов (escape sequence), показанных в табл. 3.3.

 Специальный символ      Имя                                Значение в кодировке Unicode
 \b                      Возврат на одну позицию            \u0008
 \t                      Табуляция                          \u0009
 \п                      Переход на новую строку          \ иО О Оа
 \г                      Возврат каретки                  \и О О О d
 \"                      Двойная кавычка                   \и О О 2 2
 V                       О д и н а р н а я кавычка           \u0027
 \\                      Обратная косая черта               \u005c

         Теоретически в приложении или аплете на языке Java можно использовать любой
         символ в формате Unicode, однако будет ли он отображаться на экране дисплея,
         зависит как от вашего броузера (для аплетов), так и (в конечном счете) от опера-
         ционной системы (в обоих случаях). Например, на компьютерах, работающих под
         управлением американской версии системы Windows, с помощью языка Java не-
         возможно отобразить японские иероглифы. Вопросы, связанные с интернациона-
         лизацией, рассматриваются в главе 12 в томе 2.

Булевский тип
   Переменная типа boolean имеет два значения: f a l s e и t r u e . Они используются
для вычисления логических выражений. Преобразования булевских переменных в
целочисленные и наоборот невозможны.

         В языке C++ вместо булевских величин можно использовать числа и даже ука-
         затели. Значение 0 эквивалентно булевскому значению f a l s e , а ненулевые ве-
         личины — значению t r u e . В языке Java этого нет. Следовательно, программист
         на языке Java защищен от недоразумений, связанных с использованием таких
         выражений:
         if (х = 0) // Ой! Вместо проверки х===0 выполнили присваивание!
         В языке C++ эта проверка компилируется и выполняется, причем вычисление все-
         гда приводит к результату f a l s e . В языке Java такая проверка приведет к ошибке
         компиляции, поскольку целочисленное выражение х = о нельзя преобразовать в
         булевское значение.
64    Глава 3. Основные структуры языка Java

Переменные
   В языке Java каждая переменная имеет тип. При объявлении переменной сначала
указывается ее тип, а затем — ее имя. Вот несколько примеров.
double salary;
Int vacationDays;
long earthPopulation;
char yesChar;
boolean done;
   Обратите внимание на точку с запятой после каждого объявления. Она необходи-
ма, поскольку объявление в языке Java считается оператором.
   Ниже приведены правила образования имен переменных.
   Имя переменной должно начинаться с буквы и представлять собой комбинацию
букв и цифр. Термины "буквы" и "цифры" в языке Java имеют более широкое значе-
ние, чем в большинстве других языков программирования. Буквами считаются сим-
волы ' А' —' Z ', ' а ' —' z ' , ' _ ' и любой символ в кодировке Unicode. Например, немец-
кие пользователи в именах переменных могут использовать умлауты, например, ' а', а
греческие пользователи могут воспользоваться буквой я. Аналогично цифрами счи-
таются как обычные десятичные цифры ' 0 ' - ' 9 ', так и любые символы в кодировке
Unicode, использующиеся для обозначения цифры в каком-либо языке. Символы на-
подобие ' + ' или ' © ' , а также пробел нельзя использовать в именах переменных. Все
символы в имени переменной важны, причем регистр клавиатуры также имеет значе-
ние. Длина имени переменной практически не ограничена.

          Если вы действительно хотите знать, какие символы в формате Unicode считаются
          "буквами" в языке Java, воспользуйтесь методами i s J a v a l d e n t i f i e r S t a r t и
          i s J a v a l d e n t i f i e r P a r t и з класса Character.

   В качестве имен переменных нельзя использовать зарезервированные слова.
(Список зарезервированных слов приведен в приложении.)
   В одной строке программы можно размещать несколько объявлений, например:
int i,j; // Обе переменные — целочисленные.
   Однако мы не рекомендуем такой стиль. Если объявить каждую переменную в от-
дельной строке, читать программу станет гораздо легче.

          Как видим, в языке Java различаются прописные и строчные буквы, например,
          имена h i r e d a y и h i r e D a y считаются разными. Однако иногда для переменной
          трудно подобрать хорошее имя. Многие программисты в этих случаях дают пере-
          менной имя ее типа, например:
          Box b o x ;   // -- Box — э т о т и п , a box — имя переменной.
          Однако намного лучше использовать в имени переменной префикс "а":
          Box aBox;
Присваивания и инициализации 65

Присваивания и инициализации
   После объявления переменной ее нужно явно инициализировать с помощью опе-
ратора присваивания, поскольку использовать переменную, которой не присвоено
никакого значения, невозможно. Для присвоения ранее объявленной переменной ка-
кого-либо значения нужно указать слева ее имя, поставить знак равенства (=), а справа
записать некоторое выражение на языке Java, задающее требуемое значение.
int vacationDays;     // Это — объявление.
vacationDays = 12; // Это — оператор присваивания.
   Ниже приведен пример присваивания символьной переменной некоего значения:
char yesChar;
yesChar = ' У ;
     Язык Java обладает замечательной возможностью совмещать объявление и ини-
циализацию переменной в одной строке. Например,
i n t vacationDays = 12; // Это — инициализация.
   В языке Java объявление переменной можно размещать в любом месте кода, на-
пример, приведенный ниже код вполне допустим.
double salary = 65000.0;
System.out.println(salary);
int vacationDays = 12; // Здесь можно объявить переменную.
   Разумеется, невозможно в одной и той же области видимости объявить две пере-
менные с одним и тем же именем.

         В языках С и C++ различаются объявление и определение переменной. Вот при-
         мер определения переменной:
         i n t i = 10;
         А вот пример ее объявления:
         extern i n t i ;
         В языке Java объявления и определения переменных не различаются.

Константы
  В языке Java для обозначения констант используется ключевое слово f i n a l , на-
пример:
public class Constants
    public static void main(String[] args)
         final double CM_PER_INCH = 2.54;
         double paperWidth = 8.5;
         double PaperHeight = 11;
         System.out.println("Размер страницы в сантиметрах: "
            + paperWidth * CM_PER_INCH + "на"
            + paperheight * CM_PER_INCH);

   Ключевое слово f i n a l означает, что присвоить какое-либо значение данной пе-
ременной можно лишь один раз и навсегда. Использовать в именах констант только
прописные буквы необязательно.
66          Глава 3. Основные структуры языка Java

   В языке Java часто необходимы константы, доступные нескольким методам внутри
одного класса. Обычно они называются константами класса (class constants). Констан-
ты класса объявляются с помощью ключевых слов s t a t i c f i n a l . Вот пример ис-
пользования константы класса.
public class Constants2
{
    public static final double CM_PER_INCH = 2.54;
        public static void main(String [] args)
        {
            double paperWidth = 8.5;
            double PaperHeight = 11;
            System.out.printIn("Размер страницы в сантиметрах: "
               + paperWidth * CM_PER_INCH + "на"
               + paperHeight * CM_PER_INCH);

   Отметим тот факт, что константа класса задается вне метода main. Таким образом,
ее можно использовать в других методах того же класса. Более того, если (как в дан-
ном примере) константа объявлена как p u b l i c , методы из других классов также могут
получить к ней доступ. В нашем примере это можно сделать с помощью выражения
Constants2.CM_PER_INCH.

                В языке Java слово const является зарезервированным, однако сейчас оно уже
                не употребляется. Для объявления констант следует использовать ключевое сло-
                во f i n a l .

Операторы
      Для обозначения операций сложения, вычитания, умножения и деления в языке
Java используются обычные арифметические операторы + - * /. Оператор / обо-
значает целочисленное деление, если оба его аргумента являются целыми числами.
В противном случае этот оператор обозначает деление чисел с плавающей точкой.
Остаток от деления целых чисел (т.е. функция mod) обозначается символом %. На-
пример, 15/2 равно 7, 15%2 равно 1, а 15 . 0/2 равно 7 . 5.
      Заметим, что целочисленное деление на 0 возбуждает исключительную ситуацию,
в то время как результатом деления на 0 чисел с плавающей точкой является беско-
нечность или NaN.
      Арифметические операторы можно использовать для инициализации переменных.
 i n t n = 5;
 int а = 2 * п; // Значение переменной а равно 10.
      В операторах присваивания удобно использовать сокращенные бинарные ариф-
метические операторы. Например, оператор
х += 4;
эквивалентен оператору
х   =   х   + • 4;                                       .   .   -   . . • • . . . . . , . . . - . • •

(Сокращенные операторы присваивания образуются путем приписывания символа
арифметической операции, например * или %, перед символом =, например *= или %=.)
Операторы         67

        Одной из заявленных целей языка Java является машинная независимость. Вы-
        числения должны приводить к одинаковому результату, независимо от того, какая
        виртуальная машина их выполняет. Для арифметических вычислений над числами
        с плавающей точкой это неожиданно оказалось трудной задачей. Тип double для
        хранения числовых значений использует 64 бит, однако некоторые процессоры
        применяют 80-разрядные регистры с плавающей точкой. Эти регистры обеспечи-
        вают дополнительную точность на промежуточных этапах вычисления. Рассмот-
        рим в качестве примера следующее выражение:
        double w = х * у / z;
        Многие процессоры компании Intel вычисляют выражение х * у и сохраняют этот
        промежуточный результат в 80-разрядном регистре, затем делят его на значение
        переменной z и в самом конце округляют ответ до 64 бит. Так можно повысить точ-
        ность вычислений, избежав переполнения. Однако этот результат может оказаться
        иным, если в процессе всех вычислений используется 64-разрядный процессор. По
        этой причине в первоначальном описании виртуальной машины Java указывалось,
        что все промежуточные вычисления должны округляться. Это возмутило компью-
        терное сообщество. Переполнение могут вызвать не только округленные вычисле-
        ния. На самом деле они выполняются медленнее, чем более точные вычисления,
        поскольку операции округления занимают определенное время. В результате раз-
        работчики языка Java изменили свое мнение, стремясь разрешить конфликт между
        оптимальной производительностью и отличной воспроизводимостью результатов.
        По умолчанию разработчики виртуальной машины теперь позволяют использовать
        расширенную точность в промежуточных вычислениях. Однако методы, помеченные
        ключевым словом s t r l c t f p , должны использовать точные операции над числами с
        плавающей точкой, что гарантирует воспроизводимость результатов. Например,
        метод main можно пометить ключевыми словами, как показано ниже:
        p u b l i c s t a t i c s t r i c t f p v o i d m a i n ( S t r i n g [ ] args)
        В этом случае все команды внутри метода main будут выполнять точные операции
        над числами с плавающей точкой.
        Детали выполнения этих операций тесно связаны с особенностями работы про-
        цессоров Intel. По умолчанию промежуточные результаты могут использовать
        расширенный показатель, но не расширенную мантиссу. (Микросхемы компании
        Intel поддерживают округление мантиссы без потери производительности.) Сле-
        довательно, единственное различие между вычислениями по умолчанию и точны-
        ми вычислениями состоит в том, что точные вычисления могут приводить к пере-
        полнению, а вычисления по умолчанию — нет.
        Если при чтении этого замечания ваш взгляд потускнел, не волнуйтесь. Для боль-
        шинства программистов этот вопрос совершенно не важен. Переполнение при
        вычислениях чисел с плавающей точкой в большинстве случаев не возникает. В
        этой книге мы не будем использовать ключевое слово s t r i c t f p .

Операторы инкрементации и декрементации
   Программисты, конечно, знают, что одной из наиболее распространенных опера-
ций с числовыми переменными является добавление или вычитание единицы. В язы-
ке Java, как и в языках С и C++, есть операторы инкрементации и декрементации:
оператор х++ добавляет единицу к текущему значению переменной х, а оператор х—
вычитает из него единицу. Например, код
68   Глава 3. Основные структуры языка Java

int n = 12;
делает значение переменной п равным 13. Поскольку эти операторы изменяют зна-
чение переменной, их нельзя применять к самим числам. Например, оператор 4++
является недопустимым.
     Существует два вида этих операторов. Выше показана "постфиксная" форма опе-
ратора, в которой символы операции размещаются после операнда. Есть и
"префиксная" форма— ++п. Оба этих оператора увеличивают значение переменной
на единицу. Разница между ними проявляется, только когда эти операторы использу-
ются внутри выражений. Префиксная форма оператора инкрементации сначала до-
бавляет единицу к значению переменной, в то время как постфиксная форма исполь-
зует старое значение этой переменной.
i n t m = 7;
i n t n = 7;
int a = 2 * ++m; // Теперь значение а равно 16, a m — 8.
int b = 2 * n++; // Теперь значение Ь равно 14, a n — 8.
   Мы не рекомендуем использовать оператор инкрементации ++ внутри выраже-
ний, поскольку это зачастую приводит к запутанному коду и досадным ошибкам.
   (Поскольку именно оператор ++ дал имя языку C++, это послужило поводом к пер-
вой шутке о нем. Недоброжелатели указывают, что даже имя этого языка содержит в
себе ошибку: "Кроме всего прочего, этот язык следовало бы назвать ++С, потому что
мы хотим использовать этот язык только после его улучшения".)

Операторы отношения и логические операторы
   Язык Java содержит полный комплект операторов отношения. Чтобы проверить
равенство, следует использовать символы ==. Например, значение выражения
3 == 7
равно false.
   Для проверки неравенства используются символы ! = . Так, значение выражения
3 != 7
равно t r u e .
   Кроме того, в языке Java есть обычные операторы < (меньше), > (больше),  (больше или равно).
   Язык Java, как и язык C++, использует символы && для обозначения логического опе-
ратора "и", а также символы | | для обозначения логического оператора "или" . Как
обычно, знак восклицания означает логический оператор отрицания . Операторы && и
I I вычисляются по сокращенной схеме, т.е. если в ходе вычисления выражения
А && В
выясняется, что подвыражение А ложно, то подвыражение В не вычисляется. Напри-
мер, в выражении
х != О && 1/х > х+у // Не делить на 0.
вторая часть никогда не вычисляется, если значение переменной х равно нулю. Та-
ким образом, подвыражение 1/х не вычисляется, если х равно нулю и деления на
нуль не происходит.
Операторы        69

    Аналогично, если оказывается, что выражение А истинно, то значение выражения
А | | В автоматически становится истинным, и вычислять выражение В нет необходимости.
     В языке Java есть также тернарный оператор ? :, который иногда оказывается по-
лезным. Выражение
условие ? el : е2
означает, что если условие истинно, то вычисляется выражение e l , а если ложно —
е2. Например, выражение
х < у ? х : у
вычисляет меньшее из чисел х и у.

Побитовыеоператоры
     Работая с любыми целочисленными типами, можно применять операторы, имею-
щие дело непосредственно с битами, из которых состоят целые числа. Это значит,
что для получения отдельных битов числа можно использовать технику масок. В язы-
ке Java есть следующие побитовые операторы:
S ("и")         | {"или")   '"("исключающее или")      ~("не")
Эти операторы работают с битами. Например, если п — это целое число, то выражение
i n t fourthBitFromRight = (n & 8) / 8;
равно единице, если четвертый бит справа в двоичном представлении числа п равен
единице, и нуль, если нет. Используя оператор & с соответствующей степенью двой-
ки, можно замаскировать все биты, кроме одного.

         Операторы & и | применяются к булевским переменным и вычисляют булевские
         значения. Эти операторы аналогичны операторам && и I I, за исключением того,
         что побитовые операторы не вычисляются по сокращенной схеме, т.е. перед вы-
         числением результата вычисляются оба аргумента.

     В языке Java есть также операторы >> и >, заполняющий старшие разряды нулями, в то вре-
мя как оператор » приписывает знаковый бит к старшим разрядам. Оператора > в языке
         C/C++ в действительности лишь определяет некое неотрицательное число. Язык
         Java снимает эту неопределенность.
70   Глава 3. Основные структуры языка Java

Математические функции и константы
   Класс Math содержит набор математических функций, часто оказывающихся не-
обходимыми при решении разных задач.
   Чтобы извлечь квадратный корень из числа, применяют метод s q r t .
double х = 4;

•
double у = Math.sqrt(x);
System.out.println(y); // Печатает число 2.0.

         Между методами p r i n t l n и s q r t есть небольшая разница. Метод p r i n t l n дей-
         ствует на объект System, out, имея второй параметр у — число, подлежащее вы-
         воду. (Напомним, что out — это объект, определенный в классе System и пред-
         ставляющий собой стандартное устройство вывода.) В то же время метод s q r t в
         классе Math не работает ни с одним объектом. Он имеет единственный параметр
         х — число, из которого нужно извлечь корень. Такие методы называются статиче-
         скими. Они будут изучаться в главе 4.

   В языке Java нет оператора возведения в степень: для этох-о нужно использовать
метод pow из класса Math. Оператор
double у = Math.pow(x,a) ;
присваивает переменной у значение переменной х, возведенное в степень а (х°). Оба
параметра метода pow, а также возвращаемое им значение имеют тип d o u b l e .
      Класс Math содержит обычные тригонометрические функции:
Math.sin
Math.cos
Math.tan
Math.atan
Math.atan2
   Кроме этого, в него включены экспоненциальная и обратная к ней логарифмиче-
ская функции (натуральный логарифм):
Math.exp
Math.log
В классе определены также две константы
Math.PI
Math.E,

•
обозначающие аппроксимации чисел пи е.

         Для повышения своей производительности функции в классе Math используют про-
         граммы из встроенного модуля для вычислений с плавающей точкой. Если точность
         вычислений важнее скорости их выполнения, используйте класс s t r i c t M a t h . Он
         реализует алгоритмы из библиотеки "Freely Distributable Math Library" ("Свободно
         распространяемая библиотека математических функций") f d l i b m , гарантирующей
         идентичность результатов на всех платформах. Исходные тексты программ, реали-
         зующих эти алгоритмы, можно найти на web-странице h t t p : / / w w w . n e t l i b . o r g /
         fdlibm/index .html. (В библиотеке f d l i b m дается несколько определений каждой
         функции, класс S t r i c t M a t h следует версии IEEE 754, имена функций в которой на-
         чинаются с буквы "е".)
Операторы      71

Преобразованиячисловыхтипов
    Часто возникает необходимость преобразовать один числовой тип в другой. На
рис. 3.1 показаны разрешенные преобразования.
    Шесть черных стрелок на рис. 3.1 обозначают преобразования, которые выпол-
няются без потери информации. Три серые стрелки означают преобразования, при
которых может произойти потеря точности. Например, количество цифр в большом
целом числе 123456789 превышает количество цифр, которое может быть представ-
лено типом f l o a t . Число, преобразованное в тип float, имеет правильную величи-
ну, но несколько меньшую точность.
int n = 123456789;
float f = n; // Число п равно 1.234567892Е8.

                                                char

               byte        *•   short      »•     int    *« long

                                             float      »• double
               Рис. 3.1. Разрешенные преобразования числовых типов

   Если два значения объединяются бинарным оператором (например n+f, где п —
целое число, a f — число с плавающей точкой), то перед выполнением операции оба
операнда преобразовываются в числа, имеющие одинаковый тип.
   • Если хотя бы один из операндов имеет тип double, то второй тоже преобразо-
     вывается в число типа double.
   • В противном случае, если хотя бы один из операндов имеет тип float, то вто-
     рой тоже преобразовывается в число типа float.
   • В противном случае, если хотя бы один из операндов имеет тип long, то вто-
     рой тоже преобразовывается в число типа long.
   • В противном случае оба операнда преобразовываются в числа типа i n t .

Приведениечисловыхтипов
   В предыдущем разделе мы видели, что при необходимости значения типа i n t ав-
томатически преобразовываются в значения типа double. С другой стороны, есть не-
сколько очевидных ситуаций, когда число типа double рассматривается как целое.
Преобразования чисел в языке Java возможны, однако, разумеется, при этом может
происходить потеря информации. Такие преобразования называются приведением
72        Глава 3. Основные структуры языка Java

типа (cast). Синтаксически приведение типа задается парой скобок, внутри которых
указывается желательный тип, а затем — имя переменной. Например,
double х = 9.997;
i n t nx = ( i n t ) x ;
Теперь в результате приведения значения с плавающей точкой к целому типу пере-
менная пх равна 9, поскольку при этом дробная часть числа отбрасывается.
     Если нужно округлить число с плавающей точкой до ближайшего целого числа (что
во многих случаях является намного более полезным), используется метод
Math.round.
double x = 9.997;
i n t nx = (int)Math.round(x) ;
     Теперь переменная nx равна 10. При вызове метода round по-прежнему нужно
выполнять приведение ( i n t ) , поскольку возвращаемое им значение имеет тип long,
и присвоить его переменной типа i n t можно лишь с помощью явного приведения.

              При попытке привести число одного типа к другому результат может выйти за пре-
              делы допустимого диапазона. В этом случае результат будет усечен. Например, вы-
              ражение (byte) 300 равно 44. Поэтому рекомендуется явно проверять заранее, бу-
              дет ли результат лежать в допустимом диапазоне после приведения типов.

              Приведение между булевским и целыми типами невозможно. Это предотвращает
              появление ошибок. В редких случаях для того, чтобы привести булевское значе-
              ние к числовому типу, можно использовать условное выражение b ? 1 : 0.

Скобки и иерархия операторов
   Как и во всех языках программирования, для определения порядка выполнения
операторов лучше всего использовать скобки. Однако в языке Java существует иерар-
хия операций, показанная в табл. 3.4.

 Операторы                                                           Ассоциативность
     []   .   () (вызов метода)                                      Слева направо
     I ~ ++ — +(унарный)-(унарный) () (приведение) new               Справа налево
  * / %                                                              Слева направо
                                                                     Слева направо
                                                                     Слева направо
  < < = > > = instanceof                                             Слева направо
                                                                     Слева направо
                                                                     Слева направо
                                                                     Слева направо
Строки      73

                                                                Окончание табл. 3.4
 Операторы                                                     Ассоциативность
   I                                                            Слева направо
  &&                                                            Слева направо
   II                                                           Слева направо
  ?:                                                            Слева направо
                              Л
  = += -= *=    /= %= 1=          = «= »= > » =                 Справа налево

   Если скобки не используются, операторы выполняются в указанном иерархиче-
ском порядке. Операторы, находящиеся на одном уровне иерархии, выполняются
слева направо* за исключением операторов, имеющих правую ассоциативность, как
показано в таблице.

         В отличие от языков С и C++, язык Java не имеет оператора "запятая". Однако в
         операторе f o r в качестве первого и третьего оператора можно использовать СПИ-
         СОК выражений, разделенных запятой.

Строки
   Строки— это последовательности символов, например " H e l l o " . В языке Java нет
встроенного типа для строк. Вместо этого стандартная библиотека языка Java содер-
жит встроенный класс S t r i n g . Каждая строка, заключенная в кавычки, представляет
собой экземпляр класса S t r i n g .
String e = ""; // Пустая строка.
String greeting = "Hello";

Конкатенация
   Язык Java, как и большинство языков программирования, дает возможность ис-
пользовать знак + для объединения (конкатенации) двух строк.
String expletive = "Вставка";
String PG13 = "удаленная";
String message = expletive + PG13;
     Код,    приведенный     выше,    присваивает  переменной    message     строку
"Вставкаудаленная". (Обратите внимание на отсутствие пробела между словами:
знак + объединяет две строки точно в указанном порядке.)
     При конкатенации строки со значением, которое строкой не является, это значе-
ние преобразовывается в строку. Например, код
i n t age = 13;
String r a t i n g = "PG" + age;
присваивает переменной r a t i n g строку "PG13".
     Это свойство широко используется в операторах вывода; например, оператор
System.out.println("Ответ равен " + answer);
выводит на печать все, что требуется (причем вставляет пробел после слова "равен").
74     Глава 3. Основные структуры языка Java

Подстроки
   С помощью метода s u b s t r i n g класса S t r i n g можно выделить подстроку из за-
данной строки. Например, код
String greeting = "Hello";
String s = greeting.substring(0, 4);
образует строку, состоящую из символов " H e l l " . В языке Java символы в строке под-
считываются довольно своеобразно: первый символ строки занимает нулевую пози-
цию, как и в языках С и C++. (В языке С для этого существовала техническая причина.
Однако сейчас ее уже нет, осталось лишь неудобство.)
   Например, символ ' Н ' в строке ' H e l l o ' занимает нулевую позицию, а символ
'о'— четвертую. Второй параметр метода s u b s t r i n g задает первую позицию, кото-
рую вы не хотите копировать. Допустим, что мы хотим скопировать символы из пози-
ций 0, 1, 2 и 3 (от позиции 0 до позиции 3 включительно), т.е. метод s u b s t r i n g будет
копировать символы из позиций от 0 до 4 исключительно.
   Такой способ имеет определенное преимущество: легко зычислить длину под-
строки. Строка s . s u b s t r i n g (a, b) всегда состоит из b - а символов. Например,
подстрока " Не 1 1 " имеет длину 4-0 = 4.

Редактированиестроки
     Для определения длины строки нужно использовать метод l e n g t h , например:
String g r e e t i n g = " H e l l o " ;
i n t n = g r e e t i n g . l e n g t h ( ) ; // Длина строки равна 5.
    Поскольку тип char означает символ в формате Unicode, класс S t r i n g означает по-
следовательность символов в кодировке Unicode. Из строки можно выделить отдельный
символ. Вызов метода s . char At (n) возвращает символ в кодировке Unicode, находящий-
ся в позиции п, где число п лежит в диапазоне от 0 до s . l e n g t h () --1, например:
                                                                              1
char l a s t = g r e e t i n g . c h a r A t ( 4 ) ; // Четвертый символ — ' о .
Однако класс S t r i n g не дает методов, позволяющих изменить символ в заданной
строке. Так, вы не сможете просто изменить последнюю позицию в строке g r e e t i n g ,
поместив в нее восклицательный знак, чтобы преобразовать строку g r e e t i n g в стро-
ку " H e l l ! " , . Если вы программировали на языке С, это может вызвать у вас чувство
беспомощности. Как же модифицировать строку? В языке Java это достаточно просто
сделать: выделите подстроку, которую вы хотите оставить без изменения, и конкате-
нируйте ее с символами, которые вы хотите поставить в нужные позиции:
greeting = greeting.substring(0,4) + " ! " ;
С помощью такого оператора вы можете присвоить переменной g r e e t i n g строку
"Hell!".
     Поскольку, программируя на языке Java, вы не можете изменять отдельные симво-
лы в строке, документация ссылается на объекты класса StringKiiv. на неизменные. Число
3 всегда равно 3, а строка " H e l l o " всегда содержит символы ' Н ' , ' е ' , Ч ' , ' 1 ' и
' о ' . Изменить эти значения невозможно. Однако, как мы только что убедились,
можно изменить содержимое строковой переменной g r e e t i n g и заставить ее ссылать-
ся на другую строку так же, как числовой переменной, в которой хранится число 3,
можно присвоить число 4.
Строки       75

   Не происходит ли при этом большой потери эффективности? Кажется, было бы
намного проще изменять символы, чем создавать новую строку заново. Возможно, это
и так. Действительно, неэффективно создавать новую строку, образованную с помо-
щью конкатенации строк " H e l l " и " ! " . Однако неизменяемые строки имеют одно
большое преимущество: компилятор может делать строки совместно используемыми.
   Чтобы понять этот принцип, представьте, что в некотором совместно используемом
пуле находятся разные строки. Строковые переменные указывают на некоторые ячейки в
этом пуле. При копировании строковой переменной и оригинал, и копия состоят из оди-
наковых символов, ссылаясь на одну и ту же область памяти. Кроме того, разработчики
языка Java решили, что эффективность совместного использования памяти перевешивает
неэффективность редактирования строк путем выделения подстрок и конкатенации.
   Посмотрите на свою программу; мы подозреваем, что большую часть времени вы
проводите, не изменяя строки, а сравнивая их. Разумеется, бывают случаи, когда непо-
средственные манипуляции со строками более эффективны. (Одна из таких ситуаций
возникает, когда нужно образовать строку из отдельных символов, поступающих из
файла или клавиатуры.) Для этих ситуаций язык Java предусматривает отдельный класс
StringBuf fer, который будет описан в главе 12. Если эффективность обработки строк
для вас неважна (как это часто случается во многих приложениях на языке Java), можете
проигнорировать класс S t r i n g B u f f e r и просто использовать класс S t r i n g .

         Программисты на языке С обычно попадают в тупик, когда видят строки языка
         Java в первый раз, поскольку они рассматривают строки как массив, состоящий
         из символов:
         char greeting!] = "Hello";
         Это неверная аналогия: строка в языке Java отдаленно напоминает указатель
         *char:
         char* greeting = Hello";
         При замене строки g r e e t i n g другой строкой код на языке Java выполняет при-
         мерно следующее.
         char* temp = malloc(6);
         strncpy(temp, greeting, 4);
         strncpy(temp + 4, "!", 2);
         greeting = temp;
         Разумеется, теперь переменная g r e e t i n g указывает на строку " H e l l ! " . И даже
         большинство "самых закоренелых" программистов на языке С должны признать, что
         синтаксис языка Java более элегантен, чем последовательность вызовов функции
         strncpy. А что будет, если мы присвоим строке g r e e t i n g еще одно значение?
         g r e e t i n g = "Howdy";
         Не произойдет ли утечка памяти? Ведь исходная строка размещалась в динами-
         ческой памяти. К счастью, в языке Java есть механизм автоматической сборки му-
         сора. Если блок памяти больше не нужен, он в конце концов будет освобожден.
         Если вы программируете на языке C++ и применяете класс s t r i n g , определен-
         ный в стандарте ANSI C++, вам будет намного легче работать с типом s t r i n g в
         языке Java. Объекты класса s t r i n g в языке C++ также выполняют автоматическое
         выделение и освобождение памяти. Конструкторы, операторы присваивания и
         деструкторы управляют памятью явно. Однако строки в языке C++ могут изме-
         няться — отдельные символы в строке можно модифицировать.
76 Глава 3. Основные структуры языка Java

Проверка строк на равенство
   Чтобы проверить, совпадают ли две строки, следует использовать метод equals;
вызов метода
s.equals (t)
возвращает значение true, если строки s и t равны между собой, в противном случае
он возвращает значение false. Отметим, что строки s и t могут быть как перемен-
ными, так и константами. Например, выражение
"Hello!".equals(command);
вполне допустимо. Чтобы проверить идентичность строк, игнорируя различие между
прописными и строчными буквами, следует использовать метод equalsIgnoreCase.
"Hello".equalsIgnoreCase("hello");
   Для проверки строк на равенство нельзя применять оператор ==! Он проверяет
лишь, хранятся ли обе строки в одной и той же области памяти. Разумеется, если обе
строки хранятся в одном и том же месте, они должны совпадать между собой. Однако
вполне возможна ситуация, при которой идентичные строки хранятся в разных местах.
String greeting = "Hello"; // Инициализирует переменную
                            // greeting1 строкой,
if (greeting = "Hello") ...
    // Возможно, это условие истинно.
if (greeting.substring(0, 4) == "Hell") ...
    // Возможно, это условие ложно.
   Если виртуальная машина всегда позволяет совместно использовать одинаковые
строки, то для проверки их равенства можно применять оператор ==. Однако совме-
стно использовать можно лишь константы, а не строки, являющиеся результатами та-
ких операций, как + или substring. Следовательно, либо нужно навсегда отказаться
от проверок строк на равенство с помощью оператора ==, либо вы получите про-
грамму, содержащую наихудшую из возможных ошибок — перемежающуюся ошибку,
появление которой невозможно предсказать.

         Если вы используете класс s t r i n g языка C++, будьте особенно осторожны при
         проверке строк на равенство. В классе s t r i n g оператор == перегружен и позво-
         ляет проверять идентичность содержимого строк, Возможно, в языке Java разра-
         ботчики напрасно отказались от возможности работать со строками как с число-
         выми значениями, однако это позволило сделать строки похожими на указатели.
         Разработчики могли переопределить оператор == для строк так, как это они сде-
         лали с оператором +. Что ж, каждый язык имеет свои недостатки.
         Программисты на языке С никогда не используют для проверки строк на равенст-
         во оператор ==, вместо этого они вызывают функцию s t r c m p . Метод compareTo в
         языке Java представляет собой точный аналог функции s t r c m p . Можно, конечно,
         использовать выражения вида
         i f (greeting.compareTo("Help") = = 0 ) . . .
         Однако нам кажется, что применение метода e q u a l s делает программу яснее.
Строки       77

   Класс S t r i n g в языке Java содержит более 50 методов. Неожиданно большое ко-
личество из них оказались полезными, так что можно легко себе представить, что они
используются довольно часто. Приведенное ниже замечание об интерфейсе API со-
держит наиболее полезные из них.

           Информация об интерфейсе API разбросана по всей книге для того, чтобы дать
D          вам представление о интерфейсе прикладных программ на языке Java (Java
           Application Programming Interface — API). Каждое такое замечание начинается с
           имени класса, например, j a v a . l a n g . S t r i n g — значение так называемого име-
           ни пакета разъясняется в главе 5. После имени класса указываются имена, пояс-
           нения и описание параметров одного или нескольких методов.
           Обычно в замечании не перечисляются все методы отдельного класса. Вместо этого
           из них выбираются и подробно описываются наиболее часто используемые методы.
           Полный список методов можно найти в оперативной документации о классе.

            Java.lang.String           1.0

       •     char charAt(int index)
            Возвращает символ, расположенный в указанной позиции.
       •     i n t compareTo(String other)
            Возвращает отрицательное значение, если строка предшествует строке
            other в лексикографическом порядке, положительное значение— если
            строка other предшествует данной строке в лексикографическом порядке,
            и 0 — если строки идентичны.
       •     boolean endsWith(String suffix)
            Возвращает значение t r u e , если строка заканчивается подстрокой
            suffix.
       •    boolean equals(Object other)
            Возвращает значение true, если строка равна строке other .
       •    boolean equalsIgnoreCase(String other)
            Возвращает значение true, если строка равна строке other без учета раз-
            личий между прописными и строчными буквами.
       • int index(String str)
       • int indexOf(String str, int fromlndex)
         Возвращает начало первой подстроки, совпадающей со строкой str, на-
         чиная с позиции 0 или f ormlndex.
       •    int lastlndexOf(String str)
       •    int lastlndexOf(String str, int fromlndex)
            Возвращает начало последней подстроки, равной строке str, начиная с
            позиции 0 или f ormlndex.
       •    int length()
            Возвращает длину строки.
       •    String replace(char oldChar, char newChar)
78   Глава 3. Основные структуры языка Java

         Возвращает новую строку, полученную заменой всех символов oldChar в
         строке символом newChar.
       • boolean s t a r t W i t h ( S t r i n g prefix)
         Возвращает значение true, если строка начинается подстрокой prefix.
       •  String s u b s t r i n g ( i n t beginlndex)
       •  String s u b s t r i n g ( i n t beginlndex, i n t endlndex)
         Возвращает новую строку, состоящую из всех символов, начиная с позиции
         Beginlndex и заканчивая концом строки или позицией endlndex (не
         включая ее).
       • String toLowerCase()
         Возвращает новую строку, состоящую из всех символов исходной строки,
         при этом все прописные буквы преобразовываются в строчные.
       • String toUpperCase()
         Возвращает новую строку, состоящую из всех символов исходной строки,
         при этом все строчные буквы преобразовываются в прописные.
       •    String trim()
           Возвращает новую строку, из которой исключены все предшествующие
           и замыкающие пробелы.

Чтениеоперативнойдокументации
об интерфейсе API
   Как вы только что убедились, класс String имеет много методов. Более того, в
стандартной библиотеке существует несколько сотен классов, » которых еще больше
методов. Совершенно невозможно запомнить все полезные классы и методы. Следо-
вательно, очень важно уметь пользоваться оперативной документацией об интерфей-
се API, чтобы при необходимости в стандартной библиотеке можно было найти все
классы и методы. Документация об интерфейсе API является составной частью набо-
ра инструментальных средств Java SDK. Она записана в HTML-формате. Установите
ваш броузер на подкаталог docs/api/index/html в каталоге, в котором установлен
ваш пакет Java SDK. Вы увидите экран, показанный на рис. 3.2.
   Экран разделен на три окна. В небольшом окне в правом левом углу приведены все
доступные пакеты. Под ним в окне побольше перечислены Eice классы. Щелкните
кнопкой мыши на любом из имен классов, и соответствующая документация об ин-
терфейсе API будет показана в большом окне справа (рис. 3.3). Например, чтобы по-
лучить больше информации о методах класса String, прокрутите окно, пока не уви-
дите ссылку String. Щелкните на ней.
   Затем прокрутите окно вправо, пока не увидите краткое описание всех методов,
упорядоченных в алфавитном порядке (рис. 3.4). Щелкните мышью на имени этого
метода, чтобы получить его детальное описание (рис. 3.5). Например, если вы щелк-
нете мышью на ссылке compareToIgnoreCase, то получите описание метода
compareToIgnoreCase.
Вы также можете почитать