Как использовать readInt из DataInputStream в Java?

153
27 марта 2019, 12:10

Объясните, чем логически является возвращаемое значение метода readInt() из класса DataInputStream?

В javadoc используется следующее объяснение принципа работы метода: пускай a-d являются первыми четырьмя байтами. Тогда метод вернет значение int, эквивалентное: (((a & 0xff) << 24) | ((b & 0xff) << 16) | ((c & 0xff) << 8) | (d & 0xff))

  1. Зачем тут используются конструкции вида байт & 0xFF? Как изменяется исходный байт после логического умножения на восемь единиц? Насколько я помню, исходный байт не изменяется.

  2. Непонятно, зачем используется конструкция вида байт | байт | байт | байт. Для чего используется логическое ИЛИ?

  3. Чем все-таки является возвращенный int, склеенный из четырех байтов? Логически, это же совершенно другое число. Где обычно используется этот метод?

Answer 1

Ну давайте разбираться. Вот код этого метода из JDK 11.0.1 (полагаю, что он давно не менялся)

public final int readInt() throws IOException {
    int ch1 = in.read();
    int ch2 = in.read();
    int ch3 = in.read();
    int ch4 = in.read();
    if ((ch1 | ch2 | ch3 | ch4) < 0)
        throw new EOFException();
    return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
}

Вначале тут идёт чтение четырёх байтов из InputStream поля in, которые записываются в переменные ch1, ch2, ch3, ch4. Тип этих переменных int, потому что таков тип возвращаемого значения метода InputStream#read(), несмотря на то, что на самом деле он возвращает лишь беззнаковый, то есть всегда положительный, байт в диапазоне 0..255. Тип int для байта излишен, но за счёт этой излишести метод read() может вернуть специальное значение -1, которое означает попытку прочитать байт после окончания потока данных. Именно это и проверяется в выражении (ch1 | ch2 | ch3 | ch4) < 0. Здесь производится операция ИЛИ между всеми этими числами и проверяется, что результат меньше нуля, то есть, что самый левый бит равен единице. Произойти такое может только если хотя бы одна из этих переменных меньше нуля, то есть если хотя бы у одной из них самый левый бит равен единице. Если попытки чтения после окончания потока данных не было, то мы идём дальше, иначе бросаем исключение EOFException. А дальше нам нужно построить int из наших ch1, ch2, ch3, ch4, в каждом из которых по байту. Эти байты сдвигаются на соответствующие позиции и затем "склеиваются" сложением. С тем же успехом можно было бы использовать операцию ИЛИ. Именно эта операция ИЛИ используется в javadoc описании интерфейсного метода DataInput#readInt(), вот так: (((a & 0xff) << 24) | ((b & 0xff) << 16) | ((c & 0xff) << 8) | (d & 0xff)). Операции число & 0xff здесь излишни. Они обнуляют все биты левее младшего байта. Но поскольку мы прочитали байты они и так равны нулю.

В итоге мы получили обычный знаковый int, прочитанный из четырёх байтов потока данных. Чтение происходит в порядке от старшего байта к младшему, называемом так же big-endian. Такой способ передачи данных используется при сериализации объектов Java, в протоколах TCP/IP, во многих форматах данных, например форматах изображения PNG, JPEG и прочих, в большенстве архитектур процессоров.

Существует так же обратый порядок, от младшего к старшему или little-endian. Им пользуются, например, Intel совместимые процессоры x86.

READ ALSO
Java и о всё о ней [закрыт]

Java и о всё о ней [закрыт]

Читаю документацию Java, перевожу, созрели вот такие вопросы:

266
Контейнеры Java

Контейнеры Java

программисты! Пытаюсь разобраться с контейнерамиПрограмма, используя метод add добавляет в массив из строк(изначально n=0 по размерности) заданное...

245
JavaFX - изменение текста в treeview

JavaFX - изменение текста в treeview

Есть дерево с какими-то элементамиЯ хочу, чтобы по нажатию на кнопку было можно изменить текст в выбранной ячейке

177