Java中字符串的字节数


176

在Java中,如果我有一个String x,如何计算该字符串中的字节数?


15
可能需要使用String来表示HTTP响应的正文,并使用大小来设置“ Content-Length”标头,该标头以八位字节/字节而不是字符指定。w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13
iX3 2012年

4
数据库列可能具有以字节为单位的长度限制,例如Oracle中的VARCHAR2(4000 BYTE)。人们可能想知道所需编码形式的字符串的字节数,以了解该字符串是否适合。
索姆(Somu)2013年

@ iX3与我尝试做的完全相同。
MC Emperor

1
我相信,根据意图,有两种可能的解释:一种是“我的String使用多少内存?”。答案由下面的@roozbeh提供(可能对VM的细微之处进行模化,例如压缩的OOPS)。另一个是,“如果我将字符串转换为byte [],则该字节数组将使用多少内存?”。这是Andrzej Doyle回答的问题。差异可能很大:UTF8中的“ ​​Hello World”为11个字节,但是字符串(每个@roozbeh)为50个字节(如果我的数学正确的话)。
L. Blanc

我应该补充一点,这11个字节不包括保存它们的byte []对象的开销,因此比较有些误导。
L. Blanc

Answers:


288

字符串是字符列表(即代码点)。表示字符串所用的字节数完全取决于您使用哪种编码将其转换为字节

也就是说,您可以将字符串转换为字节数组,然后按如下所示查看其大小:

// The input string for this test
final String string = "Hello World";

// Check length, in characters
System.out.println(string.length()); // prints "11"

// Check encoded sizes
final byte[] utf8Bytes = string.getBytes("UTF-8");
System.out.println(utf8Bytes.length); // prints "11"

final byte[] utf16Bytes= string.getBytes("UTF-16");
System.out.println(utf16Bytes.length); // prints "24"

final byte[] utf32Bytes = string.getBytes("UTF-32");
System.out.println(utf32Bytes.length); // prints "44"

final byte[] isoBytes = string.getBytes("ISO-8859-1");
System.out.println(isoBytes.length); // prints "11"

final byte[] winBytes = string.getBytes("CP1252");
System.out.println(winBytes.length); // prints "11"

因此,您看到,即使是简单的“ ASCII”字符串,其表示形式也可以具有不同数量的字节,具体取决于所使用的编码方式。使用您感兴趣的字符集作为的参数getBytes()。并且不要陷入假设UTF-8将每个字符都表示为单个字节的陷阱,因为这也不是真的:

final String interesting = "\uF93D\uF936\uF949\uF942"; // Chinese ideograms

// Check length, in characters
System.out.println(interesting.length()); // prints "4"

// Check encoded sizes
final byte[] utf8Bytes = interesting.getBytes("UTF-8");
System.out.println(utf8Bytes.length); // prints "12"

final byte[] utf16Bytes= interesting.getBytes("UTF-16");
System.out.println(utf16Bytes.length); // prints "10"

final byte[] utf32Bytes = interesting.getBytes("UTF-32");
System.out.println(utf32Bytes.length); // prints "16"

final byte[] isoBytes = interesting.getBytes("ISO-8859-1");
System.out.println(isoBytes.length); // prints "4" (probably encoded "????")

final byte[] winBytes = interesting.getBytes("CP1252");
System.out.println(winBytes.length); // prints "4" (probably encoded "????")

(请注意,如果不提供字符集参数,则会使用平台的默认字符集。这在某些情况下可能会很有用,但通常应避免依赖默认值,并且在编码/时始终使用显式字符集需要解码。)


1
再说一次,如果我使用getBytes()。it会给我与x.length相同的长度,是因为我不确定
Green Green

4
@Green Ash字节数组的长度-getBytes()和x.length可以相等,但不能保证相等。如果所有字符均由单个字节表示,则将相等。对于每个字符使用单个字节(或更少)的字符编码,例如ISO-8859-1,这始终适用。UTF-8使用1或2个字节,因此它取决于字符串中的确切字符。然后是一些字符编码,每个字符总是使用两个字节。
克里斯(Kris)2010年

我喜欢您的回答:),因此它们在某种程度上可能是相同的,但我并不总是对的吗?好的,那么可以使用不带参数的方法,因为这会导致我出错!
绿色

@Green的重点是字节数并不总是与字符数相同。字节数取决于所使用的字符编码。您必须知道要使用哪种字符编码,并将其考虑在内。你遇到了什么错误?如果仅使用getBytes()它,将使用系统的默认字符编码。
杰斯珀(Jesper)2010年

1
@KorayTugay是的,或多或少。但是,您可以争论因果关系的顺序。我更倾向于声明char始终为2个字节,因为它是定义为2个字节宽的原始数据类型。(而且UTF-16表示形式主要是由此产生的结果,而不是相反的结果。)
Andrzej Doyle

63

如果使用64位引用运行:

sizeof(string) = 
8 + // object header used by the VM
8 + // 64-bit reference to char array (value)
8 + string.length() * 2 + // character array itself (object header + 16-bit chars)
4 + // offset integer
4 + // count integer
4 + // cached hash code

换一种说法:

sizeof(string) = 36 + string.length() * 2

在具有压缩OOP(-XX:+ UseCompressedOops)的32位VM或64位VM上,引用为4个字节。因此总数为:

sizeof(string) = 32 + string.length() * 2

这没有考虑到对字符串对象的引用。


6
我以为问题是关于在内存中为String对象分配的字节数。正如其他人指出的那样,如果问题是关于序列化String所需的字节数,则取决于所使用的编码。
roozbeh

2
您的答案来源?谢谢
mavis

1
注意:sizeof应为8的倍数
。– Dieter

19

时髦的答案(尽管不一定是最有用的答案,具体取决于您要对结果执行的操作)是:

string.length() * 2

Java字符串以物理方式存储在UTF-16BE编码中,该编码每个代码单元使用2个字节,并String.length()以UTF-16代码单元测量长度,因此等效于:

final byte[] utf16Bytes= string.getBytes("UTF-16BE");
System.out.println(utf16Bytes.length);

这将告诉您内部char数组的大小,以字节为单位

注意:"UTF-16"将产生"UTF-16BE"与以前的编码不同的结果,因为先前的编码将插入BOM,并向数组长度增加2个字节。


Roozbeh的答案更好,因为它也考虑了其他字节。
Lodewijk Bogaards,

@finnw您确定编码为UTF-16BE而不是UTF-16吗?根据String类Javadoc(docs.oracle.com/javase/6/docs/api/java/lang/String.html),“字符串代表UTF-16格式的字符串...”。
entpnerd

17

根据如何在Java中将字符串与UTF8字节数组之间来回转换

String s = "some text here";
byte[] b = s.getBytes("UTF-8");
System.out.println(b.length);

但是对不起,当我编译您的代码时,它给我一个错误; 由于参数“ UTF-8”。当我传递一个空参数时,它的长度与x.length相同。我误解了这个概念。请帮忙
绿色环保2010年

@Green Ash,您拥有什么版本的Java?
Buhake Sindi

@Green Ash,您得到什么例外?
Buhake Sindi

2
要清楚,这是输出:test.java:11:未报告的异常java.io.UnsupportedEncodingException; 必须被捕获或声明为引发字节[] b = s.getBytes(“ UTF-8”); ^ 1错误流程已完成。
绿色

3
@Green,尝试:s.getBytes(Charset.forName("UTF-8"))
james.garriss 2014年

10

String的实例分配一定量的在存储器的字节。也许您正在寻找类似的东西sizeof("Hello World"),它会返回数据结构本身分配的字节数?

在Java中,通常不需要sizeof功能,因为我们从不分配内存来存储数据结构。我们可以看一下String.java文件进行粗略估算,然后看到一些“ int”,一些引用和一个char[]。在Java语言规范定义,一个char范围为0〜65535,所以两个字节是足以保持一个单个字符在存储器中。但是,JVM不必在2个字节中存储一个字符,它仅需保证实现char可以包含定义范围的值。

因此,sizeof在Java中确实没有任何意义。但是,假设我们有一个很大的String并char分配了两个字节,则String对象的内存占用量至少2 * str.length()为字节。


7

有一个名为getBytes()的方法。明智地使用它。


17
明智地=不要使用没有字符集参数的参数。
Thilo 2010年

为什么?如果我将环境配置为以UTF8编码运行,这是一个问题吗?
ziggy 2014年

1
getBytes还将创建并复制字节数组,因此,如果您要说的是长字符串,则此操作可能会很昂贵。
壁虱

@ticktock,如果您仍然在身边,可以,但是还有什么选择?我到这里是希望库函数返回所需的存储,以便可以将其合并为更大的分配。
SensorSmith

4

试试这个 :

Bytes.toBytes(x).length

假设您之前声明并初始化了x


3
这是标准Java库的一部分吗?我找不到Bytes班。
33Kröw

0

为避免尝试捕获,请使用:

String s = "some text here";
byte[] b = s.getBytes(StandardCharsets.UTF_8);
System.out.println(b.length);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.