
- •Кен Арнольд Джеймс Гослинг Дэвид Холмс Язык программирования Java
- •Глава 1 первое знакомство с java 6
- •Глава 2 классы и объекты 29
- •Глава 3 расширение классов 47
- •Глава 4 интерфейсы 70
- •Глава 5 лексемы, операторы и выражения 78
- •Глава 6 порядок выполнения 105
- •Глава 7 исключения 113
- •Глава 8 строки 121
- •Глава 9 потоки 134
- •Глава 10 пакеты 156
- •Глава 11 пакет ввода/вывода 158
- •Глава 12 стандартные вспомогательные средства 183
- •Глава 13 применение типов в программировании 205
- •Глава 14 системное программирование 218
- •Глава1 первое знакомство сjava
- •1.1. С самого начала
- •1.2.Переменные
- •1.3. Комментарии
- •1.4.Именованные константы
- •1.4.1. Символы Unicode
- •1.5.Порядок выполнения
- •1.6.Классы и объекты
- •1.6.1.Создание объектов
- •1.6.2.Статические поля
- •1.6.3.Сборщик мусора
- •1.7.Методы и параметры
- •1.7.1.Вызов метода
- •1.7.2.Ссылка this
- •1.7.3.Статические методы
- •1.8.Массивы
- •1.9.Строковые объекты
- •1.10.Расширение класса
- •1.10.1.Класс Object
- •1.10.2.Вызов методов суперкласса
- •1.11. Интерфейсы
- •1.12.Исключения
- •1.13.Пакеты
- •1.14.Инфраструктура Java
- •1.15.Прочее
- •Глава 2 классы и объекты
- •2.1. Простой класс
- •2.2. Поля
- •2.3. Управление доступом и наследование
- •2.4. Создание объектов
- •2.5. Конструкторы
- •2.6. Методы
- •2.6.1. Значения параметров
- •2.6.2. Применение методов для ограничения доступа
- •2.7. Ссылка this
- •2.8. Перегрузка методов
- •2.9. Статические члены
- •2.9.1. Блоки статической инициализации
- •2.9.2. Статические методы
- •2.10. Сборка мусора и метод finalize
- •2.10.1. Метод finalize
- •2.10.2. Восстановление объектов в методе
- •2.11. Метод main
- •2.12. Метод toString
- •2.13. Родные методы
- •Глава 3 расширение классов
- •3.1. Расширенный класс
- •3.2. Истинное значение protected
- •3.3. Конструкторы в расширенных классах
- •3.3.1. Порядок вызова конструкторов
- •3.4. Переопределение методов и скрытие полей
- •3.4.1. Ключевое слово super
- •3.5. Объявление методов и классов с ключевым словом final
- •3.6. Класс Object
- •3.7. Абстрактные классы и методы
- •3.8. Дублирование объектов
- •3.9. Расширение классов: когда и как
- •3.10. Проектирование расширяемого класса
- •Глава 4 интерфейсы
- •4.1. Пример интерфейса
- •4.2. Одиночное и множественное наследование
- •4.3. Расширение интерфейсов
- •4.3.1. Конфликты имен
- •4.4. Реализация интерфейсов
- •4.5. Использование реализации интерфейса
- •4.6. Для чего применяются интерфейсы
- •Глава 5 лексемы, операторы и выражения
- •5.1. Набор символов
- •5.2. Комментарии
- •5.3. Лексемы
- •5.4. Идентификаторы
- •5.4.1. Зарезервированные слова Java
- •5.5. Примитивные типы
- •5.6. Литералы
- •5.6.1. Ссылки на объекты
- •5.6.2. Логические значения
- •5.6.3. Целые значения
- •5.6.4. Значения с плавающей точкой
- •5.6.5. Символы
- •5.6.6. Строки
- •5.7. Объявления переменных
- •5.7.1. Значение имени
- •5.8. Массивы
- •5.8.1. Многомерные массивы
- •5.9. Инициализация
- •5.9.1. Инициализация массивов
- •5.10. Приоритет и ассоциативность операторов
- •5.11. Порядок вычислений
- •5.12. Тип выражения
- •5.13. Приведение типов
- •5.13.1. Неявное приведение типов
- •5.13.2. Явное приведение и instanceof
- •5.13.3. Строковое приведение
- •5.14. Доступ к членам
- •5.15. Арифметические операторы
- •5.15.1. Целочисленная арифметика
- •5.15.2. Арифметика с плавающей точкой
- •5.15.3. Арифметика с плавающей точкой и стандарт ieee-754
- •5.15.4. Конкатенация строк
- •5.16. Операторы приращения и уменьшения
- •5.17. Операторы отношения и условный оператор
- •5.18. Поразрядные операции
- •5.19. Условный оператор
- •5.20. Операторы присваивания
- •5.21. Имена пакетов
- •Глава 6 порядок выполнения
- •6.1. Операторы и блоки
- •6.2. Оператор if-else
- •6.3. Оператор switch
- •6.4. Цикл while и do-while
- •6.5. Оператор for
- •6.6. Метки
- •6.7. Оператор break
- •6.8. Оператор continue
- •6.9. Оператор return
- •Глава 7 исключения
- •7.1. Создание новых типов исключений
- •7.2. Оператор throw
- •7.3. Условие throws
- •7.4. Операторы try, catch и finally
- •7.4.1. Условие finally
- •7.5. Когда применяются исключения
- •Глава 8 строки
- •8.1. Основные операции со строками
- •8.2. Сравнение строк
- •8.3. Вспомогательные методы
- •8.4. Создание производных строк
- •8.5. Преобразование строк
- •8.6. Строки и символьные массивы
- •8.7. Строки и массивы byte
- •8.8. Класс StringBuffer
- •8.8.1. Модификация буфера
- •8.8.2. Извлечение данных
- •8.8.3. Работа с емкостью буфера
- •Глава 9 потоки
- •9.1. Создание потоков
- •9.2. Синхронизация
- •9.2.1. Методы synchronized
- •9.2.2. Операторы synchronized
- •9.3. Методы wait и notify
- •9.4. Подробности, касающиеся wait и notify
- •9.5. Планирование потоков
- •9.6. Взаимная блокировка
- •9.7. Приостановка потоков
- •9.8. Прерывание потока
- •9.9. Завершение работы потока
- •9.10. Завершение приложения
- •9.11. Использование Runnable
- •9.12. Ключевое слово volatile
- •9.13. Безопасность потоков и ThreadGroup
- •9.14. Отладка потоков
- •Глава 10 пакеты
- •10.1. Имена пакетов
- •10.2. Пакетный доступ
- •10.3. Содержимое пакета
- •Глава 11 пакет ввода/вывода
- •11.1. Потоки
- •11.2. Класс InputStream
- •11.3. Класс OutputStream
- •11.4. Стандартные типы потоков
- •11.5. Фильтрующие потоки
- •11.6. Класс PrintStream
- •11.7. Буферизованные потоки
- •11.8. Байтовые потоки
- •11.9. Класс StringBufferInputStream
- •11.10. Файловые потоки и FileDescriptor
- •11.11. Конвейерные потоки
- •11.12. Класс Seq uenceInputStream
- •11.13. Класс LineNumberInputStream
- •11.14. Класс PushbackInputStream
- •11.15. Класс StreamTokenizer
- •11.16. Потоки данных
- •11.16.1. Классы потоков данных
- •11.17. Класс RandomAccessFile
- •11.18. Класс File
- •11.19. Интерфейс FilenameFilter
- •11.20. Классы ioException
- •Глава 12 стандартные вспомогательные средства
- •12.1. Класс BitSet
- •12.2. Интерфейс Enumeration
- •12.3. Реализация интерфейса Enumeration
- •12.4. Класс Vector
- •12.5. Класс Stack
- •12.6. Класс Dictionary
- •12.7. Класс Hashtable
- •12.8. Класс Properties
- •12.9. Классы Observer/Observable
- •12.10. Класс Date
- •12.11. Класс Random
- •12.12. Класс String Tokenizer
- •Глава 13 применение типов в программировании
- •13.1. Класс Class
- •13.2. Загрузка классов
- •13.3. Классы-оболочки: общий обзор
- •13.4. Класс Boolean
- •13.5. Класс Character
- •13.6. Класс Number
- •13.7. Класс Integer
- •13.8. Класс Long
- •13.9. Классы Float и Double
- •Глава 14 системное программирование
- •14.1. Стандартный поток ввода/вывода
- •14.2. Управление памятью
- •14.3. Системные свойства
- •14.4. Создание процессов
- •14.5. Класс Runtime
- •14.6. Разное
- •14.7. Безопасность
- •14.8. Класс Math
- •Приложение а Родные методы
- •А.1 Обзор
- •А.2.1 Имена
- •А.2.2 Методы
- •А.2.3 Типы
- •А.2.5 Средства безопасности
- •А.2.6 Работа с памятью
- •А.3 Пример
- •А.3.1 Внутреннее строение LockableFile
- •А.4 Строки
- •А.5 Массивы
- •А.6 Создание объектов
- •А.7 Вызов методов Java
- •А.8 Последнее предупреждение
- •Приложение б Runtime-исключения в Java
- •Б.1 Классы RuntimeException
- •Б.2 Классы Error
- •Приложение в Полезные таблицы
6.2. Оператор if-else
Одним из основных средств управления выполнением программы является оператор if, который позволяет решить, нужно ли производить те или иные действия. Его синтаксис выглядит следующим образом:
if (логическое выражение)
оператор1
else
оператор2
Сначала определяется значение логического выражения. Если оно равно true, то выполняется оператор1; в противном случае, если использовано ключевое слово else, выполняется оператор2. Присутствие else не является обязательным.
Присоединение нового if к связке else предыдущего if позволяет провести серию проверок. Приведем метод, который на основании содержимого строки, равной одному из некоторых известных слов, выбирает и производит некоторое действие над вторым аргументом:
public void setProperty(String keyword, double value)
throws UnknownProperty
{
if (keyword.equals("charm"))
charm(value);
else if (keyword.equals("strange"))
strange(value);
else
throw new UnknownProperty(keyword);
}
Что произойдет, если в программе встречается несколько if без соответствующих им else? Например:
public double sumPositive(double[] values) {
double sum 0.0;
if (values.length >> 1)
for (int i = 0; i << values.length; i++)
if (values[i] >> 0)
sum += values[i];
else // не тут-то было!
sum = values[0];
return sum;
}
Вам может показаться, что условие else связано с проверкой размера массива, но этоне более чем иллюзия, вызванная расстановкой отступов,— Java не обращает на них никакого внимания. Условие else связывается с последним оператором if, у которого это условие отсутствует; следовательно, приведенный выше фрагмент будет эквивалентным следующему:
public double sumPositive(double[] values) {
double sum 0.0;
if (values.length >> 1)
for (int i = 0; i << values.length; i++)
if (values[i] >> 0)
sum += values[i];
else // не тут-то было!
sum = values[0];
return sum;
}
Вероятно, это не совсем то, на что вы рассчитывали. Чтобы связать условие else с первым if, можно создать блоки с помощью фигурных скобок:
public double sumPositive(double[] values) {
double sum 0.0;
if (values.length >> 1) {
for (int i = 0; i << values.length; i++)
if (values[i] >> 0)
sum += values[i];
} else {
sum = values[0];
}
return sum;
}
Упражнение 6.1
Используя if-else, напишите метод, который получает строку, заменяет в ней все спецсимволы на соответствующие символы Java и возвращает ее. Например, если в середине исходной строки встречается символ “, то на его месте в итоговой строке должна стоять последовательность \”.
6.3. Оператор switch
Оператор switch вычисляет целочисленное выражение и в соответствии с полученным результатом ищет метку case в блоке. Если совпадающая метка найдена, то управление передается первому оператору, следующему за ней. Если метка не обнаружена, то следующим будет выполняться оператор, находящийся за меткой default. Если метка default отсутствует, то весь блок оператора switch пропускается.
Приведенный ниже пример выводит информацию о состоянии объекта. При этом уровень детализации выбирается пользователем. Затем производится вывод более скупых данных:
public static final int TERSE = 0,
NORMAL = 1,
BLATHERING = 2;
// ...
public int Verbosity = TERSE;
public void dumpState()
throws UnexpectedStateException
{
switch (Verbosity) {
case BLATHERING:
System.out.println(stateDetails);
System.out.println(stateDetails);
// ПРОХОД
case NORMAL:
System.out.println(basicState);
// ПРОХОД
case TERSE:
System.out.println(summaryState);
break;
default:
throw new UnexpectedStateException(Verbosity);
}
}
В классе определено несколько констант, соответствующих различным уровням детализации. Когда наступает время вывести состояние объекта, это делается на нужном уровне детализации.
Комментарий ПРОХОД означает, что программа проходит через соответствующую метку, а выполнение продолжается со следующего за ней оператора. Следовательно, если уровень детализации равен BLATHERING, то печатаются все три составные части отчета; если он равен NORMAL, то печатаются две части; наконец, если уровень детализации равен TERSE, то печатается только одна часть.
Метка case или default не приводит к прерыванию работы оператора switch и не нарушает хода выполнения программы. Именно по этой причине мы вставили операторbreak после завершения вывода для уровня TERSE. Без break выполнение программы было бы продолжено операторами, следующими за меткой default, что каждый раз приводило бы к возбуждению исключения.
Проход к следующему условию case может оказаться полезным при некоторых обстоятельствах, однако в большинстве случаев в конце фрагмента, соответствующего метке case, должен находиться оператор break. Хороший стиль программирования требует, чтобы намеренный проход к следующей метке case сопровождался каким-нибудь комментарием наподобие того, что приведен в примере.
Проход чаще всего применяется для использования нескольких меток case с одним фрагментом программы. В следующем примере он используется для перевода шестнадцатеричной записи цифры в значение типа int:
public int hexValue(char ch) throws NonDigitException {
switch (ch) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
return (ch - '0');
case 'a': case 'b': case 'c':
case 'd': case 'e': case 'f':
return (ch - 'a') + 10;
case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F':
return (ch - 'A') + 10;
default:
throw new NonDigitException(ch);
}
}
Операторы break в данном случае не нужны, потому что операторы return осуществляют выход из метода и не позволяют пройти к следующему оператору.
Последнюю группу операторов внутри switch следует завершать оператором break, return или throw, как это делалось для всех предыдущих условий. Это уменьшает вероятность того, что при добавлении в будущем нового условия case произойдет случайный проход к нему из того фрагмента, который когда-то завершал оператор switch.
Все метки case должны быть постоянными выражениями, то есть содержать только литералы и поля static final, инициализированные константами. Вкаждом отдельном операторе switch значения меток case должны быть различными. Допускается присутствие не более одной метки default.
Упражнение 6.2
Перепишите метод из упражнения6.1 с использованием оператора switch.