如何正确计算字符串的字节数?
如何正确计算字符串的字节数?这个问题的出现是因为使用String类的length()方法或者通过调用getBytes()方法返回的字节数组来获取字符串的长度时,特殊字符没有被计算为两个字节。
String类的length()方法并不能回答问题:“有多少个字节被使用了?”而是回答了:“有多少个UTF-16码元或者简单地说有多少个字符被包含了?”
getBytes()方法可以将字符串编码为字节数组。你可以使用返回的字节数组的length属性来知道编码后使用了多少个字节,但是结果将取决于编码过程中使用的字符集。
然而,getBytes()方法并不允许指定字符集,而是使用操作系统的默认字符集。因此,如果底层操作系统默认使用的字符集与你想要用来将字符串编码为字节的字符集不一致,那么使用该方法可能得不到预期的结果。此外,根据应用程序部署的平台不同,字符串被编码为字节的方式也可能会改变,这可能是不可取的。最后,如果字符串无法在默认字符集中进行编码,行为是未指定的。因此,应谨慎使用这个方法,或者根本不使用。
在你的字符串示例“endereço”中,如果getBytes()方法返回一个大小为8而不是9的数组,那么这意味着你的操作系统不是默认使用UTF-8,而是使用了一个固定每个字符1个字节宽度的字符集,比如ISO 8859-1及其派生的字符集,比如Windows操作系统中的windows-1252。
要知道应用程序运行的当前Java虚拟机的默认字符集,可以使用以下实用方法:Charset defaultCharset = Charset.defaultCharset()。
解决方法:
getBytes()方法还有另外两个非常有用的重载方法:
- byte[] java.lang.String.getBytes(String charsetName) throws UnsupportedEncodingException
- byte[] java.lang.String.getBytes(Charset charset)
与没有参数的getBytes()方法不同,这些方法允许指定在字节编码期间要使用的字符集。
你可以使用其中之一,将字符串编码为字节数组,并以UTF-8或任何其他字符集获取其在该特定字符集下的大小。例如,要使用getBytes(String charsetName)方法获取UTF-8编码的字节数组,可以这样做:
String yourString = "endereço";
byte[] bytes = yourString.getBytes("UTF-8");
int sizeInBytes = bytes.length;
你将得到一个长度为9个字节的结果,与你期望的一样。
以下是一个更全面的示例,显示了默认编码、使用默认字符集平台的字节编码,UTF-8和UTF-16的情况:
public static void main(String[] args) throws UnsupportedEncodingException {
// default charset
Charset defaultCharset = Charset.defaultCharset();
System.out.println("default charset = " + defaultCharset);
// String sample
String yourString = "endereço";
// getBytes() with default platform encoding
System.out.println("getBytes() with default charset, size = " + yourString.getBytes().length + System.lineSeparator());
// getBytes() with specific charset UTF-8
System.out.println("getBytes(\"UTF-8\"), size = " + yourString.getBytes("UTF-8").length);
System.out.println("getBytes(StandardCharsets.UTF_8), size = " + yourString.getBytes(StandardCharsets.UTF_8).length + System.lineSeparator());
// getBytes() with specific charset UTF-16
System.out.println("getBytes(\"UTF-16\"), size = " + yourString.getBytes("UTF-16").length);
System.out.println("getBytes(StandardCharsets.UTF_16), size = " + yourString.getBytes(StandardCharsets.UTF_16).length);
}
在我的Windows操作系统上的输出结果如下:
default charset = windows-1252
getBytes() with default charset, size = 8
getBytes("UTF-8"), size = 9
getBytes(StandardCharsets.UTF_8), size = 9
getBytes("UTF-16"), size = 18
getBytes(StandardCharsets.UTF_16), size = 18
最后,需要注意的是,String的length()方法返回的是UTF-16码元的数量,而不是字节数量。一个码点可以由多个码元组成,而一个“字形簇”(大多数用户认为是一个字符)可以由多个码点组成。