Страницы

Поиск по вопросам

воскресенье, 9 февраля 2020 г.

Как именно работает метод read() у InputStream?

#java #io


Как же все-таки устроена работа метода read():


Почему метод возвращает int а не byte?
Почему возвращается byte как int в диапазоне от 0 до 255?
Почему метод не может возвращать byte?
Что вернет метод если он считает -1 из входного потока?

    


Ответы

Ответ 1



Почему метод read() класса InputStream возвращает int, а не byte? Попробуйте выполнить такой код: byte myByte = -3; // 11111101 byte[] myArray = {myByte}; InputStream in = new ByteArrayInputStream(myArray); int myInt = in.read(); System.out.println(myInt); // 253 В консоль выводится 253, а не -3. Почему так происходит? Тип данных int в Java является дополненнным до двух целым числом и использует 32 бита вместо 8. В 32х битном виде число 253 будет: 00000000000000000000000011111101 т.е. метод read() возвращает не само значение byte, а его представление в 32х битном виде. Как хранятся значения в int и в byte ? | число | 32 bit | 8 bit | ----- -------------------------------- -------- | . . | . . . . . . . . . . . . . . . . | | . . | . . . . . . . . . . . . . . . . | | -128 | 11111111111111111111111110000000 | 10000000 | | -127 | 11111111111111111111111110000001 | 10000001 | | -126 | 11111111111111111111111110000010 | 10000010 | | -125 | 11111111111111111111111110000011 | 10000011 | | . . | . . . . . . . . . . . . . . . . | . . . . | | . . | . . . . . . . . . . . . . . . . | . . . . | | -2 | 11111111111111111111111111111110 | 11111110 | | -1 | 11111111111111111111111111111111 | 11111111 | | 0 | 00000000000000000000000000000000 | 00000000 | | 1 | 00000000000000000000000000000001 | 00000001 | | 2 | 00000000000000000000000000000010 | 00000010 | | . . | . . . . . . . . . . . . . . . . | . . . . | | . . | . . . . . . . . . . . . . . . . | . . . . | | 125 | 00000000000000000000000001111101 | 01111101 | | 126 | 00000000000000000000000001111110 | 01111110 | | 127 | 00000000000000000000000001111111 | 01111111 | | . . | . . . . . . . . . . . . . . . . | | . . | . . . . . . . . . . . . . . . . | Диапазон byte в Java лежит от -128 до 127, а возвращаемое значение метода read() лежит в диапазоне от 0 до 255 Что происходит с числом byte в методе read()? Чтобы получить представление byte в int в методе read() используется побитовое «И» c числом 255, т.е. убираем лидирующие единицы. | число | 32 bit | ----- -------------------------------- | -3 | 11111111111111111111111111111101 | И | 255 | 00000000000000000000000011111111 | = | 253 | 00000000000000000000000011111101 | Чтобы из представления получить обратно значение byte в int, нужно выполнить обратную операцию побитовое «ИЛИ» c числом -256, т.е. добавляем лидирующие единицы. | число | 32 bit | ----- -------------------------------- | 253 | 00000000000000000000000011111101 | ИЛИ | -256 | 11111111111111111111111100000000 | = | -3 | 11111111111111111111111111111101 | Что происходит с числом byte == -1 в методе read()? То же самое: убираем лидирующие единицы. | число | 32 bit | ----- -------------------------------- | -1 | 11111111111111111111111111111111 | И | 255 | 00000000000000000000000011111111 | = | 255 | 00000000000000000000000011111111 |

Ответ 2



На все 4 вопроса вообще один ответ. Возвращается int потому что надо такой тип, который может вместить в себя один байт (реальные данные) плюс одно служебное значение (это тот самый -1), которое является признаком окончания чтения. Вообще конечно можно бы было спроектировать метод read() так, чтобы он возвращал byte. Но тогда этот метод в случае окончания потока либо должен был бросать исключение, либо вводить допольнительный метод, при помощи которого бы можно было проверять окончание потока. С обоими способами бы были проблемы, т.к. с исключениями у программистов всегда бы оно ловилось, а природа исключений немного другая. А с дополнительным методом нельзя заставить обязать программиста его везде вызывать (ведь если этот вызов будет опущен, то как отделить, когда из потока методом read возращается 0 с данными от 0 когда данных нет. Вообще говоря, этот метод редко используется, в основном из-за своих проблем с производительностью. Предпочтение отдаётся методу read(byte[]), который читает сразу массив байт. P.S. Другой вопрос почему тут выбрали int, а не short. Точных причин сказать не могу, но скорее потому, что short считается неполноценным братом int. Многие арифметические алгоритмы предпочитают использовать всегда int, даже когда точно известно, что диапазона short вполне хватит. И ещё есть момент с short. JVM-инструкции более заточены на int, нежели на short.

Комментариев нет:

Отправить комментарий