Пример 6.4. Канал обмена информацией
class Target extends Thread { private PipedReader pr; Target(PipedWriter pw) { try { pr = new PipedReader(pw); } catch(IOException e) { System.err.println("From Target(): " + e); } } PipedReader getStream(){ return pr; } public void run() { while(true) { try { System.out.println("Reading: " + pr.read()); } catch(IOException e) { System.out.println("The job's finished."); System.exit(0); } } } }
class Source extends Thread { private PipedWriter pw; Source() { pw = new PipedWriter(); } PipedWriter getStream() { return pw;} public void run() { for (int k = 0; k < 10; k++) { try { pw.write(k); System.out.println("Writing: " + k); } catch(Exception e) { System.err.println("From Source.run(): " + e); } } } }
public class Main { public static void main(String[] args) throws IOException { Source s = new Source(); Target t = new Target(s.getStream()); s.start(); t.start(); } }
Сериализация объектов. Методы классов ObjectInputStream и ObjectOutputStream позволяют прочитать из входного байтового потока или записать в выходной байтовый поток данные сложных типов — объекты, массивы, строки. Процесс записи объекта в выходной поток получил название сериализации (serialization), а чтения объекта из входного потока и восстановления его в оперативной памяти — десериализации (deserialization). Сериализации можно подвергнуть объекты, которые реализует интерфейс Serializable. Этот интерфейс не содержит ни полей, ни методов. По сути дела это только пометка, разрешающая сериализацию класса. class A implements Serializabie{...} Для сериализации достаточно создать объект класса ObjectOutputStream, связав его с выходным потоком, и выводить в этот поток объекты методом writeObject(). В выходной поток выводятся все нестатические поля объекта, независимо от прав доступа к ним, а также сведения о классе этого объекта, необходимые для его правильного восстановления при десериализации. Байт-коды методов класса не сериализуются. Если в объекте присутствуют ссылки на другие объекты, то они тоже сериализуются, а в них могут быть ссылки на другие объекты, которые опять-таки сериализуются, и получается целое множество связанных между собой сериализуемых объектов. Метод writeObject() распознает две ссылки на один объект и выводит его в выходной поток только один раз. К тому же, он распознает ссылки, замкнутые в кольцо, и избегает зацикливания.
Все классы объектов, входящих в такое сериализуемое множество, а также все их внутренние классы, должны реализовать интерфейс Serializable, иначе будет выброшено исключение NotSerializableException и процесс сериализации прервется. Десериализация происходит так же просто, как и сериализация. Нужно только соблюдать порядок чтения элементов потока. В примере 6.5 мы создаем объект класса GregorianCalendar с текущей датой и временем, сериализуем его в файл date.ser, через три секунды десериализуем и сравниваем с текущим временем. Пример 6.5. Сериализация объекта import java.util.*;
class SerDatef { public static void main(String[] args) throws Exception { GregorianCalendar d = new GregorianCalendar(); ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream("date.ser")); oos.writeObject(d); oos.flush(); oos.close(); Thread.sleep(3000);
ObjectInputStream ois = new ObjectInputStream( new FileInputStream("date.ser")); GregorianCalendar oldDate = (GregorianCalendar)ois.readObject(); ois.close(); GregorianCalendar newDate = new GregorianCalendar(); System.out.println("Old time = " + oldDate.get(Calendar.HOUR) + ":" + oldDate.get(Calendar.MINUTE) + ":" + oldDate.get(Calendar.SECOND) + "\nNew time = " + newDate.get(Calendar.HOUR) + ":" + newDate.get(Calendar.MINUTE) + ":" + newDate.get(Calendar.SECOND)); } }
Метод writeObject() не записывает в выходной поток поля, помеченные static и transient. Впрочем, это положение можно изменить, переопределив метод writeObject() или задав список сериализуемых полей. Вообще процесс сериализации можно полностью настроить под свои нужды, переопределив методы ввода/вывода и воспользовавшись вспомогательными классами. Можно даже взять весь процесс на себя, реализовав не интерфейс Serializable, а интерфейс Externalizable, но тогда придется реализовать методы readExternal () и writeExternal (), выполняющие ввод/вывод.
Файловые диалоги. При работе с файлами часто требуются стандартные файловые диалоги. Библиотека Swing предлагает класс JFileChooser для реализации этого функционала. JFileChooser fc = new JFileChooser(); fc.showOpenDialog(frame); File selFile = fc.getSelectedFile(); fc.showSaveDialog(frame); selFile = fc.getSelectedFile();
Практические задания
1. Изучить особенности реализации потоков ввода-вывода в Java. 2. Доработать программу, созданную в лабораторных работах № 2-5: 1) добавить в главное меню команду «Консоль». По этой команде должно появляться немодальное диалоговое окно с многострочным текстовым полем, занимающим всю область окна. В это окно можно вводить команды по варианту. В это же окно выводится реакция программы на команду; 2) для передачи команды в основное окно программы использовать каналы ввода-вывода; 3) создать конфигурационный файл для программы. В конфигурационный файл должны сохраняться все настройки симуляции, т.е. все данные и состояния, которые задаются в панели управления программы. Конфигурационный файл должен читаться при запуске программы и записываться при выходе. Формат файла текстовый; 4) добавить в главное меню команды «Загрузить» и «Сохранить». Команда «Сохранить» вызывает сериализацию всех «живых» объектов в ней. Команда «Загрузить» останавливает текущую симуляцию (если симуляция запущена) и загружает объекты из выбранного файла. После открытия симуляцию можно запустить, загруженные объекты должны вести себя естественно; 5) использовать стандартные файловые диалоги.
Вариант 1 Реализовать в консоли команды «Старт» и «Стоп» симуляции. Кнопки в интерфейсе должны вести себя так же, как если бы нажимали их, а не исполняли команды (блокироваться по очереди). Вариант 2 Реализовать в консоли команду «Вернуть количество живых пчел-рабочих/трутней». Как параметр в команду должен передаваться идентификатор вида объекта. Вариант 3 Реализовать в консоли команды «Установить вероятность рождения золотых рыбок» и «Получить вероятность рождения золотых рыбок». Как параметр в команду установки должно передаваться значение вероятности. Полученная вероятность должна выводиться на консоль. Вариант 4
Реализовать в консоли команду «Сократить число кроликов-альбиносов на N%». Как параметр в команду должно передаваться значение N%. Вариант 5 Реализовать в консоли команды «Остановить интеллектуальное поведение объектов» и «Продолжить интеллектуальное поведение объектов». Команда «Остановить» - останавливает поток расчета интеллекта объектов, а команда «Продолжить» - возобновляет расчет после остановки. Вариант 6 Реализовать в консоли команду «Уволить всех менеджеров» и «Нанять N новых менеджеров». Первая команда удаляет всех менеджеров из симуляции (новые продолжают генерироваться), вторая – генерирует N новых менеджеров. N – параметр команды. Вариант 7 Реализовать в консоли команды «Установить вероятность генерации капитальных домов» и «Получить вероятность генерации капитальных домов». Как параметр в команду установки должно передаваться значение вероятности. Полученная вероятность должна выводиться на консоль. Вариант 8 Реализовать в консоли команду «Сократить число мотоциклов на N%». Как параметр в команду должно передаваться значение N%. Вариант 9 Реализовать в консоли команды «Показывать время симуляции» и «Скрывать время симуляции». Чекбокс в интерфейсе должен вести себя так же, как если бы использовали его, а не исполняли команды (галочка появляется/исчезает). Вариант 10 Реализовать в консоли команду «Вернуть количество существующих юридических/физических лиц в картотеке». Как параметр в команду должен передаваться идентификатор вида объекта.
Вопросы для самопроверки
1. Что такое потоки ввода-вывода и для чего они нужны? 2. Какие классы Java являются базовыми для работы с потоками? 3. В чем разница между байтовыми и символьными потоками? 4. Какие стандартные потоки ввода-вывода существуют в Java, каково их назначение? На базе каких классов создаются стандартные потоки? 5. Чем является поток System.in, System.out, System.err? Какими методами чаще всего пользуются при работе с этим потоком? 6. Как создать файловый поток для чтения и записи данных?
7. В чем заключается особенность создания потока, связанного с локальным файлом? 8. Как создать поток для форматированного обмена данными, связанного с локальным файлом? 9. Как добавить буферизацию для потока форматированного обмена данными, связанного с локальным файлом? 10. За счет чего буферизация ускоряет работу приложений с потоками? 11. Когда применяется принудительный сброс буферов? 12. Для выполнения каких операций применяется класс File? 13. Для чего предназначен класс RandomAccessFile? Чем он отличается от потоков ввода и вывода? 14. Как организовать передачу объектов через потоки ввода-вывода? 15. Что такое сериализация объектов? Что такое десериализация объектов? 16. Как объявить класс сериализуемым? 17. Какие поля класса не сериализуются? 18. Как передаются данные между потоками в многопоточном приложении?
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|