Главная страница

ревью4. Потока. В данном случае мы будем говорить о потоке (stream), как об абстракции, которая используется для чтения или записи информации (файлов, сокетов, текста консоли и т д.). Объект, из которого можно считать данные, называется потоком ввода


Скачать 184.7 Kb.
НазваниеПотока. В данном случае мы будем говорить о потоке (stream), как об абстракции, которая используется для чтения или записи информации (файлов, сокетов, текста консоли и т д.). Объект, из которого можно считать данные, называется потоком ввода
Анкорревью4
Дата11.05.2023
Размер184.7 Kb.
Формат файлаpdf
Имя файларевью4.pdf
ТипДокументы
#1122926

1)
Что такое потоки ввода-вывода? Как это реализовано в Java?
В Java основной функционал работы с потоками сосредоточен в классах из пакета java.io. Ключевым понятием здесь является понятие потока. В данном случае мы будем говорить о потоке (stream), как об абстракции, которая используется для чтения или записи информации (файлов, сокетов, текста консоли и т.д.).
Объект, из которого можно считать данные, называется потоком ввода, а объект, в который можно записывать данные, - потоком вывода. Например, если надо считать содержание файла, то применяется поток ввода, а если надо записать в файл - то поток вывода.
В основе всех классов, управляющих потоками байтов, находятся два абстрактных класса: InputStream (представляющий потоки ввода) и
OutputStream (представляющий потоки вывода).
Но поскольку работать с байтами не очень удобно, то для работы с потоками символов были добавлены абстрактные классы Reader (для чтения потоков символов) и Writer (для записи потоков символов). Все остальные классы, работающие с потоками, являются наследниками этих абстрактных классов.
Какие интерфейсы реализует InputStream/ OutputStream/ Reader/
Writer?
InputStream реализует интерфейсы: Closeable и AutoCloseable
OutputStream реализует интерфейсы: Closeable, Flushable, AutoCloseable
Reader реализует интерфейсы: Closeable, AutoCloseable, Readable
Writer реализует интерфейсы: Closeable, Flushable, Appendable,
AutoCloseable
На каком паттерне основана иерархия потоков ввода/вывода?
Объекты классов Java, которые используются для ввода/вывода, для обеспечения необходимой функциональности наслаиваются друг на друга.
Такая модель взаимодействия объектов поддерживается в паттерне
«Декоратор». В этом паттерне при создании потока нужно использовать несколько объектов.
Назовите основные предки потоков ввода/вывода
Байтовые: java.io.InputStream, java.io.OutputStream;
Символьные: java.io.Reader, java.io.Writer;
В каких пакетах лежат классы-потоки?
Классы потоков ввода\вывода лежат в java.io / java.nio;
Для работы с архивами используются классы из пакета java.util

2)
Что делает метод read?
Метод read() используется для чтения символов. Метод читает следующий байт из входящего потока. Когда метод ничего не может считать (конец потока), возвращается -1. Он возвращает представление byte в 32-х битном виде.
Метод возвращает Int потому что нужно нужен такой тип, который может вместить 1 байт (0-255), плюс одно служебное значение -1, а диапазон byte в Java лежит от -128 до 127. Чтобы получить представление byte в int, в методе read() используется побитовое "И".
Что вернёт метод read() если считает (-1), а (-3)?
Вернёт 255. Если методу read() встречается байт равный -1, то он вернет значение, к которому применилось побитовое "И" с числом 255.
Если считает (-3), вернет 253
Что возвращает перегруженный read. Какое максимальное значение
вернет?
• Максимально, read может ввести 65534 байта, + индикатор ошибки (-1).
int read() - возвращает представление очередного доступного символа во входном потоке в виде целого числа.
int read(char[] buffer) - пытается прочесть максимум buffer.length символов из входного потока в массив buffer. Возвращает количество символов, в действительно сти прочитанных из потока.
int read(char[] buffer, int offset, int length) - пытается прочесть максимум length символов, расположив их в массиве buffer, начиная с элемента offset. Возвращает количество реально прочитанных символов
3)
Что такое System.in, что такое System.out?
Переменная System.out ссылается на стандартный поток вывода (по умолчанию консоль)
Переменная System.in ссылается на стандартный поток ввода (по умолчанию клавиатура)

4)
Что делает flush? Почему важно закрывать потоки?
Сбрасывает выходной поток и заставляет записывать буферные выходные байты.
Общий контракт flush состоит в том, что его вызов - это указание на то, что если какие-либо ранее записанные байты были буферизованы, такие байты должны быть немедленно записаны в предназначенный им пункт назначения.
Для обеспечения производительности данные сначала записываются в буфер. Когда буфер заполняется, данные записываются на вывод (Файл, консоль и т.д.). Когда буфер частично заполнен, но вы хотите отправить его на вывод (файл, консоль), тогда вам нужно вызвать метод flush() вручную, чтобы записать частично заполненный буфер для вывода (файл, консоль).
Почему важно закрывать потоки?
При закрытии потока освобождаются все выделенные для него ресурсы, например, файл. В случае, если поток окажется не закрыт, может происходить утечка памяти.
Можно ли использовать flush() для небуферизированного потока и что
будет?
МОЖНО среда хоста может выполнять свою собственную буферизацию, неизвестную Java. В этом случае запись можешь кэшироваться в буферах
ОС.
Гарантируется ли запись данных в файл при вызове flush()?
Если предполагаемое место назначения этого потока является абстракцией, предоставляемой базовой ОС, например файлом, то очистка потока гарантирует только то, что байты, ранее записанные в поток, передаются ОС для записи; это не гарантирует, что они действительно записаны на физическое устройство.
Выполнится ли flush если мы сделаем close у потока??
ДА, ВЫПОЛНИТСЯ Flush очищает буфер и скидывает содержимое в поток. В соответствии с документами java, вызывая close() на любом потоке java.io автоматически вызывает flush().
Какие потоки можно не закрывать (не вызывать метод close())?
Потоки с AutoCloseble интерфейсом. Например try-with-resourse.
Что делает метод available()?
Метод возвращает количество байт, которое еще осталось в потоке

5)
Расскажи про классы Reader и Writer?
Символьные потоки имеют два основных абстрактных класса Reader и Writer, управляющие потоками символов Unicode.
Абстрактный класс Reader предоставляет функционал для чтения
текстовой информации. Рассмотрим его основные методы:
absract void close(): закрывает поток ввода int read(): возвращает целочисленное представление следующего символа в потоке. Если таких символов нет, и достигнут конец файла, то возвращается число -1
int read(char[] buffer): считывает в массив buffer из потока символы, количество которых равно длине массива buffer. Возвращает количество успешно считанных символов. При достижении конца файла возвращает -1
int read(CharBuffer buffer): считывает в объект CharBuffer из потока символы.
Возвращает количество успешно считанных символов. При достижении конца файла возвращает -1
absract int read(char[] buffer, int offset, int count): считывает в массив buffer, начиная со смещения offset, из потока символы, количество которых равно count long skip(long count): пропускает количество символов, равное count.
Возвращает число успешно пропущенных символов
BufferedReader
Буферизированный входной символьный поток
CharArrayReader
Входной поток, который читает из символьного массива
FileReader
Входной поток, читающий файл
FilterReader
Фильтрующий читатель
InputStreamReader
Входной поток, транслирующий байты в символы
LineNumberReader
Входной поток, подсчитывающий строки
PipedReader
Входной канал
PushbackReader
Входной поток, позволяющий возвращать символы обратно в поток
Reader

Абстрактный класс, описывающий символьный ввод
StringReader
Входной поток, читающий из строки
Класс Writer определяет функционал для всех символьных потоков
вывода. Его основные методы:
Writer append(char c): добавляет в конец выходного потока символ c.
Возвращает объект Writer
Writer append(CharSequence chars): добавляет в конец выходного потока набор символов chars. Возвращает объект Writer abstract void close(): закрывает поток abstract void flush(): очищает буферы потока void write(int c): записывает в поток один символ, который имеет целочисленное представление void write(char[] buffer): записывает в поток массив символов absract void write(char[] buffer, int off, int len) : записывает в поток только несколько символов из массива buffer. Причем количество символов равно len, а отбор символов из массива начинается с индекса off void write(String str): записывает в поток строку void write(String str, int off, int len): записывает в поток из строки некоторое количество символов, которое равно len, причем отбор символов из строки начинается с индекса off
BufferedWriter
Буферизированный выходной символьный поток
CharArrayWriter
Выходной поток, который пишет в символьный массив
FileWriter
Выходной поток, пишущий в файл
FilterWriter
Фильтрующий писатель
OutputStreamWriter
Выходной поток, транслирующий байты в символы
PipedWriter
Выходной канал
PrintWriter
Выходной поток, включающий методы print() и println()

StringWriter
Выходной поток, пишущий в строку
Writer
Абстрактный класс, описывающий символьный вывод
Функционал, описанный классами Reader и Writer, наследуется непосредственно классами символьных потоков, в частности классами
FileReader и FileWriter соответственно, предназначенными для работы с текстовыми файлами.
6)
Как преобразовать считанные байты в символы? Какой класс для этого используется?
OutputStreamWriter — мост между классом OutputStream и классом
Writer. Символы, записанные в поток, преобразовываются в байты.
InputStreamReader — аналог для чтения. При помощи методов класса
Reader читаются байты из потока InputStream и далее преобразуются в символы. Преобразовать можем используя.io.InputStreamReader
(подкласс Reader), используем метод read(), и явное приведение к char
7)
Отличие Scanner’a от BufferedReader’a?
* Scanner имеет небольшой буфер (1KB буфер символов), а BufferedReader
(8KB байтовый буфер)
* BufferedReader работает синхронно, а Scanner — нет. BufferedReader
(работает с несколькими потоками)
* BufferedReader немного быстрее по сравнению со сканером, потому что сканер выполняет синтаксический анализ входных данных, а
BufferedReader просто читает последовательность символов.
* При использовании BufferReader нужно указывать IO Exception
Для чего нужен Scanner?
Scanner это класс в языке Java, который позволяет считывать данные из
разных источников. В том числе и с консоли.
Scanner используется для считывания введенных данных: String, byte, short, int, long, float, double
Что такое токен в Scanner?
Токен - это подстрока, не содержащая разделителей и ограниченная слева и справа разделителями. Стандартными разделителями являются: пробел, символ табуляции, перевода строки и возврата каретки.
Есть ли у Scanner буфер?

У сканнера есть буфер, его размер 1KB (Буфер символов)
8)
Отличие пакета io от nio?
Основное отличие: IO – потоко-ориентированный , а NIO - буферо- ориентированным
(IO) Потоко-ориентированный ввод/вывод подразумевает чтение/запись из потока/в поток одного или нескольких байт в единицу времени поочередно.
Блокирующий ввод-вывод
Потоки ввода/вывода (streams) в Java IO являются блокирующими.
Это значит, что когда в потоке выполнения (tread) вызывается read() или write() метод любого класса из пакета java.io.*, происходит блокировка до тех пор, пока данные не будут считаны или записаны.
Поток выполнения в данный момент не может делать ничего другого
Потоко-ориентированный ввод-вывод
Потоко-ориентированный ввод/вывод подразумевает чтение/запись из потока в поток одного или нескольких байт в единицу времени поочередно. Данная информация нигде не кэшируются. Таким образом, невозможно произвольно двигаться по потоку данных вперед или назад. Если вы хотите произвести подобные манипуляции, вам придется сначала кэшировать данные в буфере.
(NIO) – Буферо-ориентированный, данные считываются в буфер для последующей обработки.
Неблокирующий ввод-вывод
Неблокирующий режим NIO позволяет запрашивать считанные данные из канала (channel) и получать только то, что доступно на данный момент, или вообще ничего, если доступных данных пока нет. Вместо того, чтобы оставаться заблокированным пока данные не станут доступными для считывания , поток выполнения может заняться чем-то другим.
9)
Расскажи про класс File? Как создать новый файл на жестком диске?
В отличие от большинства классов ввода/вывода, класс File работает не с потоками, а непосредственно с файлами. Данный класс позволяет получить информацию о файле: права доступа, время и дата создания, путь к каталогу.
А также осуществлять навигацию по иерархиям подкаталогов.

Класс java.io.File может представлять имя определённого файла, а также имена группы файлов, находящихся в каталоге. Если класс представляет каталог, то его метод list() возвращает массив строк с именами всех файлов.
Для создания объектов класса File можно использовать один из следующих конструкторов.

File(File dir, String name) - указывается объекта класса File (каталог) и имя файла

File(String path) - указывается путь к файлу без указания имени файла

File(String dirPath, Sring name) - указывается путь к файлу и имя файла

File(URI uri) - указывается объекта URI, описывающий файл
Класс File может использоваться для создания каталога или дерева каталогов.
Также можно узнать свойства файлов (размер, дату последнего изменения, режим чтения/записи), определить к какому типу (файл или каталог) относится объект File, удалить файл. У класса очень много методов, перечислим некоторые.

getAbsolutePath() - абсолютный путь файла, начиная с корня системы.
В Android корневым элементом является символ слеша (/)

canRead() - доступно для чтения

canWrite() - доступно для записи

exists() - файл существует или нет

getName() - возвращает имя файла

getParent() - возвращает имя родительского каталога

getPath() - путь

lastModified() - дата последнего изменения

isFile() - объект является файлом, а не каталогом

isDirectory - объект является каталогом

isAbsolute() - возвращает true, если файл имеет абсолютный путь

renameTo(File newPath) - переименовывает файл. В параметре указывается имя нового имени файла. Если переименование прошло неудачно, то возвращается false

delete() - удаляет файл. Также можно удалить пустой каталог
Вызвать метод createNewFile() и передать имя файла (все вместе - инициализация объекта File)
Создать файл в Java с помощью объекта File можно тремя способами:
1. Передав в объект абсолютный путь

2. Указать только имя файла
3. Указать относительный путь (корневая директория проекта)
Какой класс предназначен для работы с элементами файловой системы
(ЭФС)?
Класс File работает непосредственно с файлами. Данный класс позволяет получить информацию о файле: права доступа, дата создания, путь к каталогу. А также осуществлять навигацию по подкаталам.
10)
В чём отличие File от Path?
* Многие методы класса File не сообщают нам никаких подробностей о возникшей проблеме или даже вообще не выдают исключений, в отличии от методов Path.
* Поддержка метаданных. Класс файла в java.io пакет имеет плохую поддержку метаданных, что приводит к проблемам на разных платформах с операциями ввода-вывода. Метаданные могут также включать разрешения, владельца файла и атрибуты безопасности. Из-за этого класс File вообще не поддерживает символические ссылки, а метод rename() не работает согласованно на разных платформах.
* Производительность Вместо File в пакете NIO появились такие классы, как Paths, Path, Files.
Методы класса File
mkdir() создает каталог
createNewFile() создает новый файл, true
delete() удаляет файл, true
renameTo() переименовывает
exists() проверяет есть ли каталог или файл, true
isDirectory() если есть каталог, true
isFile() если находится файл, true
getAbsolutePath() возвращает путь, String
getName() имя, String
getParent() имя род класса, String
list() возвращает массив файлов и каталогов
11)
В чем разница между абсолютным и относительным путем?
Абсолютный (полный) путь — это путь, который указывает на одно и то же место в файловой системе, вне зависимости от текущей рабочей директории или других обстоятельств. Полный путь всегда начинается с корневого каталога.

Относительный путь представляет собой путь по отношению к текущему рабочему каталогу пользователя или активного приложения.
Канонический путь?
Это тот путь, который будет максимально простым и строгим "каноничным". То есть, без всех этих странных конструкций. canonical
path: C:\abc\file.txt absolute path: C:\abc\..\abc\file.txt
Какой символ является разделителем при указании пути к ЭФС?
Для различных систем символ разделителя различается.
Вытащить его можно используя file.separator, а так же в статическом поле
File.separator.
Вроде как для всех систем можно использовать « \ ».
12)
Что такое клонирование? Как реализовано клонирование в Java?
Иногда необходимо на основе существующего объекта создать второй такой же - то есть создать его клон. Это процесс в Java называется клонированием.
Клонировать объект в Java можно тремя способами:
1. Использовать конструктор копирования;
2. Переопределить метод clone() и реализовать интерфейс Cloneable;
3. Использовать для клонирования механизм сериализации;
Чем отличается копирование от клонирования?
Clone - создаёт что-то новое на основе чего-то существующего.
Копирование-копирование с чего-то существующего на что-то другое
Можно ли клонировать String, массив String?
(?)
Строку нет, массив можно
13)
Как удалить директорию с файлами?
Методом delete. Директория будет удалена только в случае если в ней нет файлов, либо вложенных директорий. Чтобы удалить директорию с файлами, сначала необходимо удалить сами файлы в папке, а затем и саму папку (обычно используется рекурсия).
14)
В чём разница между поверхностным и глубоким клонированием? Как реализовать глубокое клонирование?
Поверхностное клонирование применяется только с примитивными полями (метод clone ()).

Поверхностное клонирование копирует настолько маленькую часть, насколько это возможно. По умолчанию, копирование в Java является поверхностным. В случае поверхностного клонирования создается новый объект, который имеет точную копию значений в исходном объекте. В этом механизме клонирования объект копируется без содержащихся в нем объектов. Клон копирует только структуру верхнего уровня объекта.
Реализация: необходимо реализовать интерфейс Cloneable. Если этого не сделать, при вызове метода clone() выбросится исключение
CloneNotSupportedException. Интерфейс Cloneable является маркерным (не имеет ни одного метода). Он показывает что объекты класса могут быть клонированы. Метод clone() является protected, поэтому класс может клонировать только собственные объекты. Для того, чтобы клонировать другие объекты, метод clone() нужно расширить до public.
Глубокое клонирование применяется с примитивными и ссылочным и типами. Его используют в тех случаях, когда в клонируемом классе есть изменяемые объекты.
Реализация: все классы-члены в оригинальном классе должны поддерживать клонирование.
Для каждого члена класса должен вызываться super.clone() при переопределении метода clone();
Если какой-либо член класса не поддерживает клонирование, то в методе клонирования необходимо создать новый экземпляр этого класса и скопировать каждый его член со всеми атрибутами в новый объект класса, по одному.
15)
Что такое сериализация и десериализация?
Сериализация — процесс сохранения состояния объекта в последовательность байт.
Для сериализации объектов в поток используется класс
ObjectOutputStream. Он записывает данные в поток.
Десериализация — процесс восстановления объекта из этих байт.
Для десериализации используется класс ObjetInputStream
Любой Java объект можно преобразовать в последовательность байт. Чтобы появилась возможность сериализовать объект, он должен наследовать
интерфейс Serializable. Данный интерфейс не имеет каких-либо методов, а просто дает понять системе, что объект, который реализует его, может быть сериализован.
Какие объекты можно сериализовать?
Классы имплементирующие интерфейс Serializable, поля в этих классах
Как сериализовать объект класса?

Помечаем его маркерным классом Serializable
Создаем файл, в который будем записывать объект
Затем преобразуем объект в байты
Сохраняем с помощью метода writeObject()
Что будет если перед десериализцией изменится класс? Почему будет
выброшено исключение?
Изменится поле private static final long serialVersionUID.
А затем будет выброшено исключение java.io.InvalidClassException. Если же поле создать явно и присвоить значение, то дальше уже всё зависит от того какие изменения произошли в классе, совместимые или не совместимые для сериализации.
Что делать, если одно из полей сериализовывать не нужно?
Чтобы сериализовать определенные поля, можно воспользоваться одним из двух методов:
1. Пометить это поле ключевым словом transient (приоритетно, потому что легче)
2. Использовать интерфейс Externalizable (расширение Seriazable). При использовании слова transient мы явно указываем, какие поля не нужно сериализовывать.
При использовании интерфейса Externalizable нам необходимо переопределить два метода writeExternal() и readExternal(). В методе writeExternal() мы указываем, какие поля будут сериализованы, а в readExternal() как прочитать эти поля
Externalizable vs Serializable
Интерфейс Externalizable расширяет Serializable и позволяет реализовать полностью свой механизм сериализации (стандартно запишется только идентификатор класса)
Простота, удобство – Serializable (весь контроль над сериализацией достается JVM)
Производительность – Externalizable
Гибкость – Externalizable (в Serializable можно только исключать / добавлять поля)
Безопасность – Externalizable (Иногда необходимо шифрование данных)
Что будет при сериализации объекта у которого есть поле и оно не
Serializable?
Код скомпилируется
В процессе выполнения вылетит исключение NotSerializableException
Если это поле находится в классе, от которого наследуется класс, над которым будет проходить сериализация, то это поле должно быть доступно напрямую или через геттеры и сеттеры классу, над которым будет проходить сериализация. В этом классе придется реализовать пользовательскую сериализацию.

Ещё один из приемлемых вариантов — это пометить поле transient, чтобы оно игнорировалось во время процессов сериализации и десериализации
Что если при десериализации поменять тип?
Если при десериализации поменять тип поля, то можно получить исключение ClassCastException.
Особенность сериализации поля final (Можно ли сериализовать и
десериализовать final)?
Поля с модификатором final сериализуются как и обычные. За одним исключением
- их невозможно десериализовать при использовании
Externalizable.
Поскольку final-поля должны быть инициализированы в конструкторе, а после этого в readExternal изменить значение этого поля будет невозможно. Соответственно, если необходимо сериализовать объект с final-полем необходимо использовать только стандартную сериализацию
(Serializable).
16)
Назовите несколько форматов сериализации.
Основные форматы сериализации:
JSON / YAML / XML / BSON
17)
Какие поля не сериализуются?
Помеченные ключевым словом transient и static.
18)
Как сериализовать статическое поле?
При стандартной сериализации, поля с модификатором static не
сериализуются. Соответственно, после десериализации это поле значение не поменяет. При использовании реализации Externalizable сериализовать и десериализовать статическое поле можно, но не рекомендуется этого делать, т.к. это может сопровождаться трудноуловимыми ошибками.
Что такое паттерн проектирования «Адаптер»?
Адаптер - это структурный паттерн проектирования, который позволяет подружить несовместимые объекты. Адаптер это преобразование интерфейса класса в другой интерфейс, который нужен клиенту.

Классическая реализация паттерна Class Adapter подразумевает использование множественного наследования (имплементация интерфейсов)
Пример адаптера и декоратора из IO?
Адаптер в IO - InputStreamReader
Декоратор в IO - BufferedInputStream паттерн Декоратор динамически наделяет объект новыми возможностями и является альтернативой субклассированию в области расширения функциональности
Селекторы
Селекторы в NIO позволяют одному потоку выполнения мониторить несколько каналов ввода.
Вы можете зарегистрировать несколько каналов с селектором, а потом использовать один поток выполнения для обслуживания каналов, имеющих доступные для обработки данные, или для выбора каналов, готовых для записи.
Что вы знаете о RandomAccessFile?
Класс RandomAccessFile наследуется напрямую от Object. Предназначен для работы с файлами, поддерживая произвольный доступ к их содержимому.
RandomAccessFile реализует интерфейсы DataInput и DataOutput.
RandomAccessFile содержит методы для чтения и записи примитивов и строк UTF-8.
Метод seek() позволяет переместиться к определенной позиции и изменить хранящееся там значение.
Какие есть режимы доступа к файлу?
RandomAccessFile может открываться в режиме чтения («r») или чтения/записи («rw»).
Также есть режим «rws», когда файл открывается для операций чтения- записи и каждое изменение данных файла немедленно записывается на физическое устройство.
Какие классы позволяют архивировать объекты?
DeflaterOutputStream, InflaterInputStream, ZipInputStream, ZipOutputStream,
GZIPInputStream, GZIPOutputStream
Что вы знаете об интерфейсе FilenameFilter?
Интерфейс FilenameFilter применяется для проверки попадает ли объект
File под некоторое условие.

Этот интерфейс содержит единственный метод boolean accept(File pathName). Этот метод необходимо переопределить и реализовать.
Что такое «каналы»? (файловые каналы)
Канал представляет открытое соединение с источником или адресатом ввода-вывода.
Классы каналов реализуют интерфейс Channel (расширяющий интерфейс
AutoCloseable)
Например, канал типа FileChannel поддерживает методы для получения и установки текущей позиции, передачи данных между файловыми каналами, получения текущего размера канала и его блокировки
Что вы знаете о классах-надстройках?
Классы-надстройки наделяют существующий поток дополнительными свойствами.
Примеры классов: BufferedOutputStream, BufferedInputStream,
BufferedWriter — буферизируют поток и повышают производительность.
Какой класс-надстройка позволяет ускорить чтение/запись за счет
использования буфера?
Для этого используются классы, позволяющие буферизировать поток:
BufferedInputStream
BufferedOutputStream
BufferedReader
BufferedWriter
Какой класс-надстройка позволяет читать данные из входного
байтового потока в формате примитивных типов данных?
Для чтения байтовых данных (не строк) применяется класс
DataInputStream.
В этом случае необходимо использовать классы из группы InputStream.


написать администратору сайта