【问题标题】:Java : Char vs String byte sizeJava:字符与字符串字节大小
【发布时间】:2012-03-22 15:21:13
【问题描述】:

惊讶地发现下面的代码

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

输出这个:

字符大小:2

字符串大小:1

我假设单个字符串应该占用与单个字符相同(或更多)的字节。

我特别想知道。

如果我有一个包含多个字段的 java bean,它的大小将如何增加取决于字段的性质(字符、字符串、布尔值、向量等...)我假设所有 java 对象都有一些(可能是最小的)足迹,并且这些足迹中最小的一个将是单个字符。为了测试这个基本假设,我从上面的代码开始 - 打印语句的结果似乎违反直觉。

任何关于 java 默认存储/序列化字符与字符串的方式的见解都会非常有帮助。

【问题讨论】:

标签: java string char byte


【解决方案1】:

getBytes() 使用默认编码(很可能是ISO-8859-1)输出String,而内部字符 char 始终有 2 个字节。 Java 在内部总是使用 2 字节字符的 char 数组,如果您想了解更多关于编码的信息,请阅读问题 cmets 中 Oded 提供的链接。

【讨论】:

  • 作为参考,getBytes() 实际上并没有告诉您String 的实际内存消耗。
  • 我不认为你的这种说法是正确的:“Java 内部总是使用 2 字节字符的字符数组。”你可以看到这个链接:javarevisited.blogspot.com.tr/2012/01/… 对于我来说,Java 在代码中使用 UTF-8 作为默认编码。
  • @KorayTugay 您可能混淆了 Java 中 Unicode 的内部存储器表示是什么(是的,像 String 这样的每个 CharSequence 实现仍然使用 UTF-16 格式的 2 字节字符)和 Java 导入或以特定字节编码导出内部表示(文件、网络)。如果您仍然相信您的 Java 版本(即...?)在内部使用 UTF-8,您是如何证明这一点的?顺便说一句,getBytes() 的问题是这个函数太老了,在 1.1 版本还不支持 UTF-8 的时候就已经有了,所以你不能真正预测它使用的是 UTF-8。
【解决方案2】:

我想说我的想法,如果我错了,请纠正我,但您发现字符串的长度正确显示为 1,因为字符串中只有 1 个字符。长度显示长度而不是大小。长度和大小是两个不同的东西。

检查这个Link.. 你发现占用的字节数是错误的

【讨论】:

    【解决方案3】:

    好吧,你有 char 数组中的 1 个字符的大小为 2 个字节,并且你的 String 包含的长度是 1 个字符,而不是它有 1 个字节大小。

    Java 中的String 对象包括:

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

    只有这样才能保证String 对象大于char 数组。 如果您想了解有关对象大小的更多信息,还可以阅读有关 char 数组的对象头和多重因子的信息。例如herehere

    【讨论】:

    • 这没有意义,你可以尝试提高语法...等吗?
    【解决方案4】:

    我想先添加一些代码,然后再解释一下:

    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 方法提供任何参数。可能,您正在获取字符“a”的 UTF-8 表示的字节。

    好吧,但是当我们要求 UTF-16 时,为什么我们得到了 4 个字节?好的,Java 内部使用 UTF-16,那么我们应该得到 2 个字节吧?

    如果你检查输出:

    feff061
    

    Java 实际上返回给我们一个 BOM:https://en.wikipedia.org/wiki/Byte_order_mark

    所以前 2 个字节: feff 是用于指示后续字节将是 UTF-16 Big Endian 的信号。请参阅维基百科页面了解更多信息。

    剩下的 2 个字节:0061 是你拥有的字符“a”的 2 个字节表示。可以验证来自:http://www.fileformat.info/info/unicode/char/0061/index.htm

    所以是的,Java 中的一个字符是 2 个字节,但是当您要求没有特定编码的字节时,您可能并不总是得到 2 个字节,因为不同的编码对于不同的字符需要不同的字节数。

    【讨论】:

      【解决方案5】:

      Character 的 SIZE 是 char 所需的存储空间,为 16 位。字符串的长度(也是底层 char-array 或 bytes-array 的长度)是字符数(或字节数),而不是位大小。

      这就是为什么您必须将大小除以 8,而不是长度。长度需要乘以 2。

      另请注意,如果您指定不同的编码,您将获得其他长度的字节数组。在这种情况下,执行 getBytes() 时会执行到单一或可变大小编码的转换。

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

      【讨论】:

      • 不,他用的是getBytes(),所以他得到的实际上是字节数(这也不足为奇)。
      • 是的,这个答案有点离题,并且错误地描述了问题......我建议更新。
      猜你喜欢
      • 2017-04-22
      • 2016-11-20
      • 2012-04-21
      • 1970-01-01
      • 2011-03-22
      • 2013-12-05
      • 1970-01-01
      • 2012-08-14
      相关资源
      最近更新 更多