Java 11 Compact Strings магия за символом [] и байтом [] - PullRequest
2 голосов
/ 05 марта 2019

В последние два дня я читал о кодировании Unicode Java 9 compact Strings, и у меня все хорошо. Но есть кое-что, чего я не понимаю.

О типе байтовых данных

1). Это 8-битный диапазон хранения от -128 до 127

Вопросы

1). Почему Java не реализовала это как 16-битные символы без знака? я имею в виду, что он будет в диапазоне 0,256, потому что от 0 до 127 я могу хранить только значение Ascii, но что произойдет, если я установлю значение 200, расширенный ascii переполнится до -56.

2). Означает ли отрицательное значение то, что я имею в виду, я попробую простой пример с использованием Java 11

final char value = (char)200;//in byte would overflow
final String stringValue = new String(new char[]{value});
System.out.println(stringValue);//THE SAME VALUE OF JAVA 8

Я проверил переменную String.value и вижу массив байтов

System.out.println(value[0]);//-56

Те же вопросы, что и прежде, возникают, означает ли -56 что-то, что я имею в виду (отрицательное значение), в других языках это переполнение обнаружено для возврата к значению 200? Как Java может знать, что значение -56 такое же, как 200 в char.

Я пробовал самые сложные примеры, такие как кодовая точка 128048, и я вижу в переменной String.value массив байтов, подобных этому.

0 = 61 
1 = -40
2 = 48
3 = -36

Я знаю, что эта кодовая точка занимает 4 байта, но я понимаю, как преобразуется char [] в байт [] , но я не знаю, как String обрабатывает эти байтовые [] данные.

Извините, если этот вопрос прост, и извините, любой набор английского не мой естественный язык. Большое спасибо.

Ответы [ 2 ]

5 голосов
/ 05 марта 2019

Почему Java не реализовала это как 16-битные символы без знака?я имею в виду, что он будет в диапазоне 0,256, потому что только от 0 до 127 я могу держать значение Ascii, но что произойдет, если я установлю значение 200, расширенный ascii будет переполнен до -56.Примитивные типы данных Java были установлены в Java 1.0 четверть века назад.Компактные строки были введены в Java 9 менее двух лет назад.Эта новая функция, которая является просто подробностью реализации, не оправдывает фундаментальных изменений в системе типов Java.

Кроме того, вы смотрите на одну интерпретацию данных, хранящихся в байте.Ради представления единиц iso-latin-1 совершенно не имеет значения, приведет ли интерпретация тех же данных, что и встроенная в Java подписанная byte, к положительному или отрицательному числу.

Аналогично вводу-выводу в JavaAPI позволяет считывать файл в массив byte[] и записывать массивы byte[] обратно в файлы, и этих двух операций уже достаточно для копирования файла без потерь, независимо от формата файла, который был бы важен при интерпретации его содержимого.

Итак, начиная с Java 1.1 работает следующее:

byte[] bytes = "È".getBytes("iso-8859-1");
System.out.println(bytes[0]);
System.out.println(bytes[0] & 0xff);
-56
200

Два числа, -56 и 200, являются просто различными интерпретациями битовой комбинации 11001000, тогда как iso-latin-1 интерпретация byte, содержащая битовую комбинацию 11001000, является символом È.

Значение char также является просто интерпретацией двухбайтовой величины, то есть как код UTF-16Блок.Аналогично, массив char[] - это последовательность байтов в памяти компьютера со стандартной интерпретацией.

Мы также можем интерпретировать другие последовательности байтов следующим образом.

StringBuilder sb = new StringBuilder().appendCodePoint(128048);
byte[] array = new byte[4];
StandardCharsets.UTF_16LE.newEncoder()
    .encode(CharBuffer.wrap(sb), ByteBuffer.wrap(array), true);
System.out.println(Arrays.toString(array));

напечатает значениевы видели, [61, -40, 48, -36].

Преимущество использования массива byte[] внутри класса String состоит в том, что теперь можно выбрать интерпретацию для использования iso-latin-1, когда всесимволы могут быть представлены с помощью этой кодировки или utf-16 в противном случае.

Возможные числовые интерпретации не имеют отношения к строке.Однако, когда вы спрашиваете: «Как Java может знать, что значение -56 равно 200», вы должны спросить себя, как он узнает, что битовая комбинация 11001000 для byte в первую очередь -56?

System.out.println(value[0]);

несет действительно дорогостоящую операцию, по сравнению с обычной компьютерной арифметикой, преобразование byte (или int) в String.Эта операция преобразования часто упускается из виду, так как она была определена как способ печати byte по умолчанию, но не более естественна, чем преобразование в String, интерпретирующее значение как число без знака.Для дальнейшего чтения я рекомендую Дополнение к двум .

2 голосов
/ 05 марта 2019

Это потому, что не все байты в строке интерпретируются одинаково. Это зависит от кодировки строки .

Пример:

  • если строка является строкой UTF-8, ее символы будут иметь размер 8 бит.
  • в строке UTF-16, ее символы будут иметь размер 16 бит.
  • и т.д ...

Это означает, что если строка должна быть представлена ​​как UTF-8, символы будут создаваться чтением по 1 байту за раз; если 16 бит, символы будут созданы путем чтения 2 байтов за раз.

Посмотрите на этот код: массив байтов data преобразуется в строку с использованием UTF-8 и UTF-16.

byte[] data = new byte[] {97, 98, 99, 100};
System.out.println(new String(data, StandardCharsets.UTF_8));
System.out.println(new String(data, StandardCharsets.UTF_16));

Вывод этого кода:

abcd // 4 bytes = 4 chars, 1 byte per char
慢捤  // 4 bytes = 2 chars, 2 byte per char

Возвращаясь к вопросу, что побудило разработчиков сделать это - уменьшить объем памяти на строках. Не все строки используют все 16-битные предложения char.

РЕДАКТИРОВАТЬ: код здесь

...