Java: Char против строкового байта. - PullRequest
7 голосов
/ 22 марта 2012

Привет, ребята: я был удивлен, обнаружив, что следующий код

System.out.println("Character size:"+Character.SIZE/8);
System.out.println("String size:"+"a".getBytes().length);

Выводит это:

Размер символа: 2

Размер строки: 1

Я бы предположил, что строка из одного символа должна занимать те же (или более) байты, что и один символ.

В частности, мне интересно ---

Если у меня есть Java-бин с несколькими полями, как его размер будет увеличиваться в зависимости от природы полей (Character, String, Boolean,Вектор и т. Д.) Я предполагаю, что все java-объекты имеют некоторый (возможно, минимальный) размер, и что одним из самых маленьких из этих элементов будет один символ.Итак ... Чтобы проверить это основное предположение, я начал с приведенного выше кода - и результаты операторов печати кажутся нелогичными.

Любое понимание того, как java хранит / сериализует символы против строк по умолчанию, было бы очень полезно ... спасибо.

Ответы [ 5 ]

10 голосов
/ 22 марта 2012

getBytes() выводит String с кодировкой по умолчанию (наиболее вероятно ISO-8859-1), тогда как внутренний символьный символ всегда имеет 2 байта.Внутренне Java всегда использует массивы символов с 2-байтовым символом. Если вы хотите узнать больше о кодировке, прочитайте ссылку на Oded в комментариях к вопросу.

2 голосов
/ 22 марта 2012

Я хотел бы сказать, что я думаю, поправьте меня, если я ошибаюсь, но вы находите правильную длину строки, которая отображается как 1, поскольку у вас есть только 1 символ в строке.длина показывает длину, а не размер.длина и размер - две разные вещи.

отметьте это Ссылка .. вы обнаружите, что количество байтов занято неправильно

0 голосов
/ 28 января 2016

Я хочу сначала добавить некоторый код, а затем немного пояснений:

import java.nio.charset.Charset;

public class Main {

    public static void main(String[] args) {
        System.out.println("Character size: " + Character.SIZE / 8);
        final byte[] bytes = "a".getBytes(Charset.forName("UTF-16"));
        System.out.println("String size: " + bytes.length);
        sprintByteAsHex(bytes[0]);
        sprintByteAsHex(bytes[1]);
        sprintByteAsHex(bytes[2]);
        sprintByteAsHex(bytes[3]);
    }

    static void sprintByteAsHex(byte b) {
        System.out.print((Integer.toHexString((b & 0xFF))));
    }
}

И результат будет:

Character size: 2
String size: 4
feff061

Итак, чего вы на самом деле упускаете, так это того, что выне предоставляют никаких параметров для метода getBytes .Возможно, вы получаете байты для UTF-8 представления символа «a».

Хорошо, но почему мы получили 4 байта, когда мы запросили UTF-16?Хорошо, Java использует UTF-16 внутренне, тогда мы должны были получить 2 байта правильно?

Если вы изучите вывод:

feff061

Java фактически вернула нам спецификацию: https://en.wikipedia.org/wiki/Byte_order_mark.

Таким образом, первые 2 байта: feff необходимы для сигнализации следующегобайтами будет UTF-16 Big Endian.Пожалуйста, обратитесь к странице Википедии для получения дополнительной информации.

Оставшиеся 2 байта: 0061 - это 2-байтовое представление имеющегося у вас символа "a".Можно проверить по: http://www.fileformat.info/info/unicode/char/0061/index.htm

Так что да, символ в Java составляет 2 байта, но когда вы запрашиваете байты без определенной кодировки, вы не всегда можете получить 2 байта, так как для разных кодировок потребуется разное количествобайтов для различных символов.

0 голосов
/ 22 марта 2012

хорошо, у вас есть 1 символ в массиве символов, имеющий размер 2 байта, и длина вашей строки равна 1 символу, а не 1 байту.

Объект String в Javaсостоит из:

private final char value[];
private final int offset;
private final int count;
private int hash;

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

0 голосов
/ 22 марта 2012

РАЗМЕР Символа - это хранилище, необходимое для символа, которое составляет 16 бит. Длина строки (также длина основного char-массива или байтового массива) - это количество символов (или байтов), а не размер в битах.

Вот почему вы делали деление на 8 для размера, но не для длины. Длина должна быть умножена на два.

Также обратите внимание, что вы получите другие длины для байтового массива, если вы укажете другую кодировку. В этом случае при выполнении getBytes () было выполнено преобразование в кодировку с одним или различным размером.

См .: http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#getBytes(java.nio.charset.Charset)

...