#java #io
#java #io
Вопрос:
В последние дни я читал о потоках в Java. Прочитав совсем немного, я начинаю понимать, что название «поток» было выбрано из-за сходства с тем, о чем мы используем это слово в «реальной жизни», например, о воде. И что необязательно знать, откуда поступают данные. Пожалуйста, исправьте, если я неправильно это истолковал.
Но я этого не понимаю. Например, когда я говорю getOutputStream
или getInputStream
в сокете, я получаю InputStream
который я могу связать с тем, что мне нравится. Но разве InputStream / OutputStream не абстрактные классы? Я не знаю точно, как это правильно объяснить, но я не понимаю, что соединение с сокетом, просто вызывая этот метод, автоматически создает поток / канал, по которому могут проходить байты / символы? Что на самом деле является InputStream / OutputStream? Являются ли потоки способом абстрагирования реальных источников?
Я думаю, что понимаю различные способы их объединения в цепочки, однако я чувствую, что упускаю суть концепции.
Из-за отсутствия надлежащего способа объяснить это, я удалю вопрос, если он плохой.
Спасибо за ваше время.
Ответ №1:
InputStream
/ OutputStream
это, ну, абстракции. Они предоставляют вам некоторый базовый API для чтения / записи байтов или групп байтов, не раскрывая фактическую реализацию. Давайте возьмем OutputStream
в качестве примера:
OutputStream
получает кучу байтов через общедоступный API. На самом деле вы не знаете (и не заботитесь), что происходит с этими байтами впоследствии: они отправляются. Реальная реализация может: добавлять их в файл, игнорировать их ( NullOutputStream
в Apache Commons), сохранять их в памяти или… отправка через сокет.
Вот что происходит при вызове Socket.getOutputStream()
: вы получаете некоторую реализацию OutputStream
, просто вам все равно, это зависит от реализации и специфично. Когда вы отправляете байты в этот поток, базовая реализация будет передавать их с использованием TCP / IP или UDP. Фактически TCP / IP сам по себе является потоковым протоколом, хотя он работает с пакетами / фреймами.
Аналогичная ситуация для InputStream
— вы получаете некоторую реализацию из сокета. Когда вы запрашиваете у потока несколько байтов, базовая InputStream
реализация запросит у сокета OS такое же количество байтов, возможно, блокируя. Но в этом и заключается настоящее удовольствие от наследования: вам все равно! Просто используйте эти потоки любым удобным для вас способом, объединяя в цепочки, буферизуя и т.д.
Комментарии:
1. Отлично, спасибо. Это было то, что я искал, на самом деле, где я должен остановиться относительно того, что происходит.
Ответ №2:
При вызове getInputStream
сокет возвращает экземпляр некоторого конкретного подкласса InputStream
. Обычно вы не беспокоитесь о точном классе возвращаемого объекта; поскольку это InputStream
, вы просто работаете с ним таким образом. (Подкласс может даже быть частным вложенным классом класса socket.)
Ответ №3:
InputStream
действительно является абстракцией. В каждом случае может использоваться другая реализация концепции потока. Но пользователю потока не нужно знать, какова была точная реализация.
В случае Socket
реализация является SocketInputStream
, которая расширяет FileInputStream
Ответ №4:
Я не думаю, что это плохой вопрос. Вы совершенно правы в том, что потоки абстрагируют от вас сложность того, откуда поступают данные, и делают их единообразными. Следовательно, вы можете написать код, который считывает данные из файла или сокета, и этот код может выглядеть практически идентично. Это означает, что вам обычно приходится писать меньше кода.
Когда вы получаете InputStream из сокета, вы можете получить доступ к любым данным, поступающим в этот сокет. При чтении из этого потока, как правило, вы предоставляете массив байтов и просите поток заполнить его за вас. Он будет считывать столько данных, сколько доступно, или он заполнит буфер. Вам решать, что вы будете делать с данными в этом массиве байтов.
Для любого типа ввода-вывода сокетов, хотя, сказав все это о потоках, Java socket API довольно старый, и есть несколько действительно хороших доступных альтернатив, которые его дополняют и проще в использовании. Я настоятельно рекомендую Netty, используя который, вы можете забыть о потоках и сосредоточиться на POJOs и на том, как их кодировать и декодировать.