恐怕我有一个关于一个相当饱和的主题的细节的问题,我搜索了很多次,但是没有找到一个明确的答案来回答这个明显的-不重要的问题:
当使用UTF-8将byte[]转换为字符串时,每个字节(8位)都会变成一个由UTF-8编码的8位字符,但在java中,每个UTF-8字符都保存为16位字符。对吗?如果是,这意味着每个愚蠢的java字符只使用前8位,并消耗两倍的内存?这也是正确的吗?我想知道这种浪费的行为怎么能被接受。
有一个8位的伪串是不是有一些诀窍?这实际上会减少内存消耗吗?或者,有没有一种方法可以在一个>two< 16位字符中存储Java8位字符来避免这种内存浪费?
感谢你给我解开的答案。
编辑:嗨,感谢大家的回复。我知道UTF-8的可变长度属性。然而,由于我的源是8位字节,我理解(显然是错误的)它只需要8位UTF-8字。UTF-8转换是否真的保存了您在CLI上执行"cat somebinary“时看到的奇怪符号?我认为UTF-8只是以某种方式将字节的每个可能的8位字映射到UTF-8的一个特定的8位字。不对?我考虑过使用Base64,但它很糟糕,因为它只使用了7位。
重新制定的问题:有没有更聪明的方法将字节转换成字符串?我最喜欢的是将byte[]转换为char[],但我仍然有16位字。
其他用例信息:
我采用Jedis ( NoSQL Redis的java客户端)作为hypergraphDB的“原始存储层”。因此,jedis是另一个“数据库”的数据库。我的问题是,我必须一直向jedis提供byte[]数据,但在内部,>Redis< (实际的服务器)只处理“二进制安全”字符串。因为Redis是用C语言写的,所以一个字符是8位的,而AFAIK不是7位的ASCIII。然而,在Jedis中,java世界中,每个字符在内部都是16位长。我还不理解这段代码,但是我想jedis会把这个java的16位字符串转换成一个符合Redis的8位字符串((here)。它说它扩展了FilterOutputStream。我希望完全绕过byte[] <->字符串转换,使用Filteroutputstream...?)
现在我在想:如果我必须一直转换byte[]和字符串,数据范围从非常小到可能非常大,在java中将每个8位字符作为16位传递,不是非常浪费内存吗?
发布于 2011-04-12 21:56:13
有一个8位的伪串是不是有一些诀窍?
是的,请确保您拥有最新版本的Java。;)
http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html
-XX:+UseCompressedStrings对字符串使用byte[],它可以表示为纯ASCII码。(在Java 6 Update 21性能版本中引入)
编辑:此选项在Java 6更新22中不起作用,并且在Java 6更新24中默认为打开。注意:此选项可能会使性能降低约10%。
下面的程序
public static void main(String... args) throws IOException {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++)
sb.append(i);
for (int j = 0; j < 10; j++)
test(sb, j >= 2);
}
private static void test(StringBuilder sb, boolean print) {
List<String> strings = new ArrayList<String>();
forceGC();
long free = Runtime.getRuntime().freeMemory();
long size = 0;
for (int i = 0; i < 100; i++) {
final String s = "" + sb + i;
strings.add(s);
size += s.length();
}
forceGC();
long used = free - Runtime.getRuntime().freeMemory();
if (print)
System.out.println("Bytes per character is " + (double) used / size);
}
private static void forceGC() {
try {
System.gc();
Thread.sleep(250);
System.gc();
Thread.sleep(250);
} catch (InterruptedException e) {
throw new AssertionError(e);
}
}缺省情况下打印此内容
Bytes per character is 2.0013668655941212
Bytes per character is 2.0013668655941212
Bytes per character is 2.0013606946433575
Bytes per character is 2.0013668655941212使用选项-XX:+UseCompressedStrings
Bytes per character is 1.0014671435440285
Bytes per character is 1.0014671435440285
Bytes per character is 1.0014609725932648
Bytes per character is 1.0014671435440285发布于 2011-04-12 20:12:30
实际上,您对UTF-8部分的理解是错误的: UTF-8是一种可变长度的多字节编码,因此存在长度为1-4字节的有效字符(换句话说,一些UTF-8字符是8位的,一些是16位的,一些是24位的,还有一些是32位的)。虽然1字节字符占据了8位,但还有更多的多字节字符。如果您只有1个字节的字符,则总共只能有256个不同的字符(也称为“扩展的ASCII");这可能足以满足英语中90%的使用(我的天真猜测),但只要你想到这个子集之外的任何东西,就会咬你的屁股(参见单词天真-英语,但不能只用ASCII编写)。
因此,尽管UTF-16 ( Java使用的)看起来很浪费,但实际上并非如此。无论如何,除非您在一个非常有限的嵌入式系统上(在这种情况下,您在那里用Java做什么?),否则试图精简字符串是毫无意义的微优化。
有关字符编码的稍微长一点的介绍,请参见例如:http://www.joelonsoftware.com/articles/Unicode.html
发布于 2011-04-12 20:29:05
使用UTF-8将byte[]转换为字符串时,每个字节(8位)都会变成一个由UTF-8编码的8位字符
不是的。当使用UTF-8将byte[]转换为String时,每个1-6字节的UTF-8 序列被转换为1-2个16位字符的UTF-16 序列。
在世界范围内,几乎所有情况下,此UTF-16序列都包含单个字符。
在西欧和北美,对于大多数文本,仅使用此16位字符的8位。然而,如果你有一个欧元符号,你将需要超过8位。
有关详细信息,请参阅Unicode。或者Joel Spolsky's article。
https://stackoverflow.com/questions/5634855
复制相似问题