Пример 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. Как передаются данные между потоками в многопоточном приложении?
Дата добавления: 2018-04-15; просмотров: 356; Мы поможем в написании вашей работы! |
Мы поможем в написании ваших работ!