Слайд 2Основы ввода/вывода
Реальные приложения Java не основаны на консольных текстовых программах.
Они являются графическими апплетами, которые для взаимодействия с пользователем полагаются
на систему классов AWT (Abstract Window Toolkit, инструментарий абстрактного окна) языка Java.
Поддержка Java для консольного ввода/вывода ограничена и не очень удобна в использовании — даже в простых примерах программ.
Текстовый консольный ввод/вывод в действительности не очень важен для Java-программирования.
Несмотря на это, Java обеспечивает сильную, гибкую поддержку по существу текстового ввода/вывода для файлов и сетей. Система ввода/вывода Java связна и непротиворечива.
Слайд 3Потоки
Java-программы выполняют ввод/вывод через потоки.
Поток является абстракцией, которая или
производит, или потребляет информацию.
Поток связывается с физическим устройством с
помощью системы ввода/вывода Java (Java I/O system).
Все потоки ведут себя одинаковым образом, хотя фактические физические устройства, с которыми они связаны, могут сильно различаться.
Таким образом, одни и те же классы и методы ввода/вывода можно применять к устройствам любого типа.
Поток ввода может извлекать много различных видов входных данных: из дискового файла, с клавиатуры или сетевого разъема.
Поток вывода может обратиться к консоли, дисковому файлу или сетевому соединению (сокету).
Благодаря потокам ваша программа выполняет ввод/вывод, не понимая различий между клавиатурой и сетью.
Java реализует потоки с помощью иерархии классов, определенных в пакете java.io.
Слайд 4Байтовые и символьные потоки
Java 2 определяет два типа потоков (точнее
— поточных классов и объектов): байтовый и символьный.
Байтовые потоки
предоставляют удобные средства для обработки ввода и вывода байтов. Байтовые потоки используются, например, при чтении или записи данных в двоичном коде.
Символьные потоки предоставляют удобные средства для обработки ввода и вывода символов. Они используют Unicode и поэтому могут быть интернационализированы. Кроме того, в некоторых случаях символьные потоки более эффективны, чем байтовые.
На самом низком уровне весь ввод/вывод все еще байтовый. Символьно-ориентированные потоки обеспечивают удобные и эффективные средства для обработки символов.
Слайд 5Классы байтовых потоков
Байтовые потоки определяются в двух иерархиях классов.
Наверху
этой иерархии — два абстрактных класса: Inputstream и Outputstream.
Каждый
из этих абстрактных классов имеет несколько конкретных подклассов, которые обрабатывают различия между разными устройствами, такими как дисковые файлы, сетевые соединения и даже буферы памяти.
Абстрактные классы Inputstream и Outputstream определяют несколько ключевых методов, которые реализуются другими поточными классами. Два наиболее важных— read() и write(), которые, соответственно, читают и записывают байты данных.
Оба метода объявлены как абстрактные внутри классов inputstream и outputstream и переопределяются производными поточными классами.
Слайд 7Классы символьных потоков
Символьные потоки определены в двух иерархиях классов. Наверху
этой иерархии два абстрактных класса: Reader и Writer.
Они обрабатывают
потоки символов Unicode.
Абстрактные классы Reader и Writer определяют несколько ключевых методов, которые реализуются другими поточными классами.
Два самых важных метода — read() и write(), которые читают и записывают символы данных, соответственно.
Они переопределяются производными поточными классами.
Слайд 9Предопределенные потоки
Все программы Java автоматически импортируют пакет java.lang.
Этот пакет
определяет класс с именем system, инкапсулирующий некоторые аспекты исполнительной среды
Java.
Класс system содержит также три предопределенные поточные переменные in, out и err. Эти поля объявлены в System со спецификаторами public и static.
Объект System.out называют потоком стандартного вывода. По умолчанию с ним связана консоль.
На объект System.in ссылаются как на стандартный ввод, который по умолчанию связан с клавиатурой.
К объекту System.err обращаются как к стандартному потоку ошибок, который по умолчанию также связан с консолью.
Однако эти потоки могут быть переназначены на любое совместимое устройство ввода/вывода.
Слайд 10Чтение консольного ввода
Консольный ввод в Java выполняется с помощью считывания
из объекта System.in.
Чтобы получить символьный поток, который присоединен к
консоли, вы переносите ("упаковываете") System.in в объект типа BufferedReader.
Класс BufferedReader поддерживает буферизированный входной поток. Обычно используется следующий его конструктор:
BufferedReader(Reader inputReader)
где inputReader — поток, который связан с создающимся экземпляром класса BufferedReader.
Reader — абстрактный класс. Один из его конкретных подклассов — это InputStreamReader, который преобразовывает байты в символы.
Чтобы получить InputStreamReader-объект, который связан с System.in, используйте следующий конструктор:
InputstreamReader(InputStream inputstream)
Поскольку System.in ссылается на объект типа inputstream, его можно использовать в качестве параметра inputstream.
Следующая строка кода создает объект класса BufferedReader, который связан с клавиатурой:
BufferedReader br = new BufferedReader(new InputstreamReader(System.in));
После того как этот оператор выполнится, объектная переменная br станет символьным потоком, связанным с консолью через System.in.
Слайд 11Чтение символов
Для чтения символа из BufferedReader используйте метод read(). Версия
read(), которую мы будем применять, такова:
int read() throws IOException
При каждом
вызове read() читает символ из входного потока и возвращает его в виде целочисленного значения. Когда read о сталкивается с концом потока, то возвращает -1. Как вы видите, он может выбрасывать исключение ввода/вывода (I/O-исключение — IOException).
Слайд 12Чтение символов
// Использует BufferedReader для чтения символов с консоли,
import
java.io.*;
class BRRead
{
public static void main(String args [ ])
throws IOException
{
char c;
BufferedReader br = new
BufferedReader(new InputStreamReader(System.in));
System.out.println("Введите символы, 'q' - для завершения.");
// чтение символов
do
{
с = (char) br.read();
System.out.println(с);
}
while(c != 'q');
}
}
Слайд 13Чтение строк
Для чтения строки, вводимой с клавиатуры, используйте версию метода
readLine(), который является элементом класса BufferedReader. Его обшая форма:
String readLine()
throws IOException
Как видно, он возвращает string-объект.
Слайд 14Чтение строк
// Крошечный редактор.
import java.io..*;
class TinyEdit {
public static void main(String
args[];
throws IOException (
// Создать BufferedReader-объект,используя System.in
BufferedReader br = new
BufferedReader(new
InputStreamReader(System.in));
String str[] = new String[100];
System.out.println("Введите строки текста.");
System.out.println("Введите 'stop' для завершения.");
for (int i=0; i<100; i++)
{
str[i] = br.readLine();
if(str[i].equals("stop"))
break; }
System.out.println(“\n Вот ваш файл:");
// Вывести строки на экран.
for (int i=0; i<100; i++) {
if(str[i].equals("stop")) break;
System.out.println(str[i]); }
} }
Слайд 15Запись консольного вывода
Консольный вывод легче всего выполнить с помощью методов
print () и println().
Эти методы определены классом Printstream (который
является типом (классом) объекта System.out).
Поскольку PrintStream — выходной поток, производный от OutputStream, онтакже реализует метод нижнего уровня write().
Самая простая форма write (), определенная в Printstream, имеет вид:
void write (int byteval) throws lOException
Этот метод записывает в файл байт, указанный в параметре byteval. Хотя byteval объявлен как целое число, записываются только младшие восемь битов.
Слайд 16Запись консольного вывода
// Демонстрирует System.out.write.
class WriteDemo {
public static void
main(String args[])
{
int b;
b = 'A';
System.out.write(b);
System.out.write('\n');
}
}
Вы не часто будете применять write () для выполнения консольного вывода (хотя это может быть полезно в некоторых ситуациях), потому что использовать print() println() намного легче.
Слайд 17Класс PrintWriter
Хотя использование объекта System.out для записи на консоль все
еще допустимо в Java, его применение рекомендуется главным образом для
отладочных целей или для демонстрационных программ, типа тех, которые показаны в этой книге.
Для реальных Java-программ для записи на консоль рекомендуется работать с потоком типа PrintWriter.
PrintWriter — это один из классов символьного ввода/вывода. Использование подобного класса для консольного вывода облегчает интернационализацию вашей программы.
PrintWriter определяет несколько конструкторов. Мы будем использовать следующий:
PrintWriter (OutputStream OutputStream, boolean flushOnNewline)
Здесь OutputStream — объект типа OutputStream; flushOnNewline — булевский параметр, используемый как средство управления сбрасыванием выходного потока в буфер вывода (на диск) каждый раз, когда выводится символ newline (\n). Если fiushOnNewilne — true, поток сбрасывается автоматически, если — false, то не автоматически.
Printwriter поддерживает методы print () и println() для всех типов, включая Object.
Чтобы записывать на консоль, используя класс Printwriter, создайте объект System.out для выходного потока, и сбрасывайте поток после каждого символа newline.
Например, следующая строка кода создает объект типа Printwriter, который соединен с консольным выводом:
PrintWriter pw = new Printwriter(System.out, true);
Слайд 18Класс PrintWriter
// Демонстрирует Printwriter.
import java.io.*;
public class PrintWriterDemo
{
public static
void main(String args[j])
{
Printwriter pw = new Printwriter(System.out, true);
pw.printIn("Это строка:");
int
i = -7;
pw.println(i);
double d = 4.5e-7;
pw.println(d);
}
Вывод этой программы:
Это строка:
-7
4.5Е-7
Слайд 19Чтение и запись файлов
Java обеспечивает ряд классов и методов, которые
позволяют читать и записывать файлы.
Для Java все файлы имеют
байтовую структуру, a Java обеспечивает методы для чтения и записи байтов в файл.
Java позволяет упаковывать байтовый файловый поток в символьно-ориентированный объект. (Об этом позже).
Для создания байтовых потоков, связанных с файлами, чаше всего используются два поточных класса — FilelnputStream и FileOutputStream.
FilelnputStream (String fileName) throws FileNotFoundException
FileOutputStream (String fileName) throws FileNotFoundException
где fileName определяет имя файла, который вы хотите открыть.
Когда вы создаете входной поток при отсутствующем файле, выбрасывается исключение FileNotFoundException.
Для выходных потоков, если файл не может быть создан, выбрасывается такое же исключение (FileNotFoundException).
Когда выходной файл открывается, любой файл, существовавший ранее с тем же самым именем, разрушается.
Слайд 20Чтение и запись файлов
После завершения работы с файлом, его нужно
закрыть, вызвав метод close(). Он определен как В FilelnputStream, так
и в FileOutputStream в следующей форме:
void close() throws IOException
Для чтения файла можно использовать версию метода read (), который определен в FilelnputStream.
int read() throws IOException
При каждом вызове он (метод) читает один байт из файла и возвращает его в форме целочисленного значения. Когда read о встречает символ конца файла (EOF), то возвращает -1.
Слайд 21Чтение и запись файлов
/* Выведет на экран текстовый файл.
При запуске
программы укажите (в параметре команды запуска) имя файла, который вы
хотите просмотреть. Например, чтобы просмотреть файл с именем TEST.TXT, Используйте следующую командную строку
Java ShowFile TEST.TXT */
import j ava.io.*;
class ShowFile
{
public static void main(String args[])
throws IOException {
int i ;
FilelnputStream fin;
try
{
fin = new FilelnputStream(args[0]);
}
catch(FileNotFoundException e)
{
System.out.println("Файл не найден");
return;
}
catch(ArraylndexOutOfBoundsException e)
{
System.out.println("Используйте: ShowFile имя_файла");
return;
}
// читать символы файла, пока
// не встретится символ EOF
Do
{
i = fin.read();
if(I != -1) System.out.print((char) i);
}
while (i != -1) ;
in.close ();
}
}
Слайд 22Апплеты
Все предшествующие примеры в этой книге были Java-приложениями.
Однако приложение
— это только один тип Java-программ.
Другой тип программ представлен
апплетом – небольших приложений, которые доступны на Internet-сервере, транспортируются по Internet, автоматически устанавливаются и выполняются как часть Web-документа.
После того, как апплет прибывает к клиенту, он имеет ограниченный доступ к ресурсам системы, которые использует для создания произвольного мультимедийного интерфейса пользователя и выполнения комплексных вычислений без риска заражения вирусами или нарушения целостности данных.
Апплеты отличаются от приложений в нескольких ключевых областях.
Слайд 23Апплеты
import java. awt. *;
Import java.applet.*;
public class SimpleApplet extends Applet
{
public void paint(Graphics g) {
g.drawstring ("A 'Simple Applet",
20, 20);
}
}
Апплет начинается; с двух операторов import.
Первый импортирует AWT (Abstract Windowing Toolkit) - абстрактный оконный интерфейс классы.
Следующая строка в программе объявляет класс SimpleApplet. Он должен быть объявлен как public, потому что к нему необходимо обеспечить доступ из кодов, которые находятся вне программы.
Внутри SimpleApplet объявлен метод paint(). Этот метод определен в AWT и должен быть переопределен апплетом. Метод paint о вызывается каждый раз, когда апплет должен восстанавливать изображение своего вывода.
Метод paint() вызывается также, когда апплет начинает выполнение.
Метод имеет один параметр типа Graphics, через который получает графический контекст, описывающий графическую среду выполнения апплета.
Внутри paint() находится обращение к методу drawstring (), который является членом класса Graphics. Этот метод выводит строку, начиная, с указанных его аргументами (х, у)-координат в окне апплета. Он имеет следующую общую форму:
void drawstring (String massage, int x, int y)
Слайд 24Апплеты
Существует два способа выполнения апплета:
Выполнение апплета Java-совместимом Web-браузером, типа Netscape
Navigator или Microsoft Internet Explorer.
Использование программы просмотра апплетов, типа стандартной
утилиты JDK appletviewer. Программа просмотра апплетов выполняет апплет в его окне.
Для выполнения апплета в Web-браузере нужно записать короткий текстовый файл в формате языка HTML, который содержит специальный тег
Слайд 25Апплеты
Несколько ключевых моментов.
Апплеты не нуждаются в методе main().
Апплеты должны
выполняться программой просмотра апплетов или браузером,
поддерживающим Java.
Пользовательский ввод/вывод в апплетах не выполняется с помощью Java-классов поточного ввода/вывода. Вместо этого апплеты используют
интерфейс, обеспеченный системой AWT.
Слайд 26Модификаторы transient и volatile
Когда экземплярная переменная объявлена как transient, то
ее значение не будет запомнено при сохранении объекта. Например:
class T
{
transient int a; // не будет сохраняться
int b; // будет сохраняться
}
Модификатор volatile сообщает компилятору, что переменная, модифицированная с его помощью, может быть неожиданно изменена другими частями вашей программы.
Слайд 27Использование instanceof
Иногда полезно распознавать тип объекта во время выполнения.
Например,
можно иметь один поток выполнения для генерации различных типов объектов,
а другой — для их обработки. В этой ситуации обрабатывающему процессу полезно было бы знать тип каждого объекта, принимаемого на обработку.
В Java недопустимое приведение вызывает ошибку времени выполнения. Много недопустимых приведений можно перехватить во время компиляции. Однако операции приведения, связанные с типами объектов (т. е. с иерархиями классов), могут оказаться недопустимыми и могут быть обнаружены только во время выполнения.
Операция instanceof имеет следующую общую форму:
object instanceof type
где object — экземпляр класса; type — класс (как тип). Если object-операнд имеет тип или его тип может быть приведен к типу, указанный в type-операнде, то результат операции instanceof имеет значение true. Иначе, ее результат — false. Таким образом, instanceof — это средство, с помощью которого ваша программа может получить информацию о типе объекта во время выполнения.
Операция instanceof не нужна для большинства программ, потому что, вообще-то, вы знаете тип объекта, с которым работаете.
Слайд 28Native-методы
Иногда может возникнуть желание вызвать подпрограмму, которая написана на другом
языке, а не на Java.
Как правило, такая подпрограмма существует
как выполняемый код для CPU и среды, в которой вы работаете — то есть как "родной" (native) код.
Однако из-за того, что Java-программы компилируются в байт-код, который затем интерпретируется (или компилируется "на лету") исполнительной системой Java, казалось бы, невозможно вызвать подпрограмму native-кода изнутри Java-программы.
В Java существует ключевое слово native, которое используется для объявления методов native-кода. После объявления эти методы можно вызывать внутри Java-программы точно так же, как вызывается любой другой метод Java.
Для объявления native-метода нужно предварить его заголовок модификатором native, при этом, однако, не следует определять никакого тела. Например:
public native int meth();
После объявления native-метода, следует записать сам родной метод и выполнить довольно сложную процедуру для связи его с кодом Java.
Большинство родных методов записываются на С. Механизм, используемый для интеграции С-кода с Java-программой, называется JNI (Java Native Interface — native-интерфейс Java).
Слайд 29Native-методы
// Простой пример, который
//использует native-метод,
public class NativeDemo {
int
i;
public static void main(String args[])
{ NativeDemo ob = new
NativeDemo();
ob.i = 10;
System.out.println("Этот ob.i перед native-методом:" + ob.i);
ob.testO;// вызов native-метода
System.out.println("Этот ob.i после native-метода:" + ob.i); }
// объявить native-метод public native
void test ();
// загрузить DLL, который содержит static-метод
static {
System.loadLibrary("NativeDemo"); } }
Заметим, что метод test () объявлен как native и не имеет тела. Он будет реализован на С.
Обратите также внимание на блок static. Как объяснялось ранее, static-блок выполняется только один раз, когда программа начинает выполняться (или, более точно, когда его класс впервые загружается).
В данном случае он используется для загрузки DLL(Dynamic Link Library)-библиотеки, которая содержит native-реализацию метода test ().
Библиотека загружается методом loadLibrary (), который является частью класса system. Вот его общая форма:
static void loadLibrary(String filename)
Здесь filename — строка, которая специфицирует имя файла, содержащего библиотеку.
Слайд 30Проблемы native-методов
Потенциальный риск безопасности. Поскольку native-метод выполняет фактический машинный код,
он может получать доступ к любой части хост-системы. То есть
native-код не ограничен средой выполнения Java. Это может привести к заражению вирусом, например. По этой же при чине native-методы не могут использовать апплеты. Загрузка DLL-файлов может быть ограничена и подчинена одобрению руководителя службы безопасности.
Потеря мобильности. Поскольку native-код содержится в DLL-файле, он должен присутствовать на машине, выполняющей программу Java. Далее, так как любой native-метод зависит от CPU и операционной системы, каждый такой DLL-файл неизбежно непереносим. Таким образом, приложение Java, которое использует native-методы, будет способно выполниться только на машине, где был установлен соответствующий DLL-файл.