- •Кен Арнольд Джеймс Гослинг Дэвид Холмс Язык программирования 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
- •Приложение в Полезные таблицы
14.4. Создание процессов
Как упоминалось выше, в программах Java могут одновременно выполняться несколько потоков. Большинство систем, на которых функционирует среда Java, также поддерживают запуск нескольких программ. Приложения Java могут вызывать новые программы, обращаясь к одной из двух форм метода System.exec. Каждый успешный вызов exec создает новый объект Process, который представляет собой работающую программу. Вы можете запросить информацию о состоянии процесса и вызвать методы, управляющие его ходом. Существуют две основные формы метода exec:
public Process exec(String[] cmdarray)throws IOException
Выполняет в текущей системе команду, заданную в объекте cmdarray, и возвращает объект Process (описанный ниже), который представляет запущенный процесс. В cmdarray[0] задается имя команды, а во всех последующих строках массива— аргументы.
public Process exec(String command)throws IOException
Эквивалентен первой форме exec, в которой элементы массива собраны в одну строку и разделены символами-разделителями. Приведем пример использования этой формы exec:
String cmd = “/bin/ls” + opts + “ ” + dir;
Process child = Runtime.getRuntime().exec(cmd);
Порожденный процесс носит название процесса-потомка (child process ). По аналогии, создающий процесс называется родителем. Метод exec возвращает объект Process для каждого запущенного процесса-потомка. Этот объект обладает двумя важными аспектами по отношению к процессу-потомку: во-первых, он содержит методы для обращения ко входному и выходному потоку процесса-потомка, а также к его потоку ошибок:
public abstract OutputStream getOutputStream()
Возвращает поток OutputStream, соединенный со входным потоком процесса-потомка. Данные, записанные в этот поток, считываются процессом-потомком в качестве ввода. Поток является буферизованным.
public abstract InputStream getInputStream()
Возвращает поток InputStream, соединенный с выходным потоком процесса-потомка. Когда процесс-потомок записывает выходные данные, они могут читаться из этого потока. Поток является буферизованным.
public abstract InputStream getErrorStream()
Возвращает поток InputStream, соединенный с выходным потоком ошибок процесса-потомка. Когда процесс-потомок выдает сообщения об ошибках, они могут читаться из этого потока. Поток является небуферизованным, чтобы гарантировать немедленное поступление информации об ошибках .
Ниже в качестве примера приводится программа, которая соединяет стандартные потоки Java с потоками нового процесса, чтобы весь ввод пользователя поступал в указанную программу, а весь ее вывод был виден пользователю:
public static Process UserProg(String cmd)
throws IOException
{
Process proc = Runtime.getRuntime().exec(cmd);
plugTogether(System.in, proc.getOutputStream());
plugTogether(System.out, proc.getInputStream());
plugTogether(System.err, proc.getErrorStream());
return proc;
}
Предполагается, что метод plugTogether соединяет два потока, читая данные из одного из них и записывая их в другой.
Упражнение 14.1
Напишите метод plugTogether. Подсказка: воспользуйтесь многопоточной моделью.
Второй аспект взаимоотношений между процессом-родителем и процессом-потомком заключается в том, что объект Process содержит методы для управления процессом и определения его статуса:
public abstract int waitFor()throws InterruptedException
Сколь угодно долго ожидает завершения процесса-потомка и возвращает значение, переданное им методу System.exit или его аналогу (ноль означает успешное завершение, все остальное— неудачу). Если процесс уже завершился, то просто возвращается значение.
public abstract int exitValue()
Возвращает завершающий код данного процесса. Если процесс еще активен, то exitValue возбуждает исключение IllegalStateException.
public abstract void destroy()
Уничтожает процесс. Ничего не делает, если процесс уже завершился. Если объект Process будет уничтожен сборщиком мусора, это не означает уничтожения самого процесса; просто в дальнейшем вы не сможете контролировать его.
Например, следующий метод возвращает строковый массив, который содержит результаты работы команды ls с заданными параметрами. В случае неудачного завершения команды возбуждается исключение LSFailedException:
// java.io.* и java.util.* импортированы
public String[] ls(String dir, String opts)
throws LSFailedException
{
try {
// запустить процесс
String[] cmdArray = { "/bin/ls", opts, dir };
Process child = Runtime.getRuntime().exec(cmdArray);
DataInputStream
in = new DataInputStream(child.getInputStream());
// прочитать выходные данные
Vector lines = new Vector();
String line;
while ((line = in.readLine()) != null)
lines.addElement(line);
if (child.waitFor() != 0) // если выполнение ls
// было неудачным
throw new LSFailedException(child.exitValue());
String[] retval = new String{lines.size()];
lines.copyInto(retval);
return retval;
} catch (LSFailedException e) {
throw e;
} catch (Exception e) {
throw new LSFailedException(e.toString());
}
}
Класс Process является абстрактным. Каждая реализация Java должна содержать один или несколько классов, расширяющих Process, которые могут взаимодействовать с процессами на уровне операционной системы. Такие классы могут обладать расширенным набором функций, полезных для программирования в данной среде. Информация о расширенных функциях должна содержаться в документации.
Две другие формы exec позволяют задать набор переменных среды (environment variables )— системно-зависимых переменных, доступных для нового процесса. Переменные среды передаются методу exec в виде строкового массива, каждый элемент которого задает имя и значение переменной среды в форме имя = значение. Имя не может содержать пробелов, хотя значение может быть произвольным. Переменные среды передаются вторым параметром:
public Process exec(String command, String[] env)
throws IOException
public Process exec(String[] command, String[] env)
throws IOException
Способ интерпретации переменных среды процессом-потомком является системно-зависимым. Механизм переменных среды поддерживается потому, что он существует на самых разных платформах. Для передачи информации между Java-программами следует пользоваться свойствами, а не переменными среды.
Упражнение 14.2
Напишите программу, которая выполняет exec для аргументов, переданных в командной строке, и выводит результаты работы, причем каждой строке предшествует ее номер.
Упражнение 14.3
Напишите программу, которая выполняет exec для аргументов, переданных в командной строке, и выводит результаты, прекращая работу процесса, когда на выходе появляется заранее определенная строка.