使用特定的字符集将byte []转换为String时,避免创建“new”String对象

时间:2009-10-16 14:32:10

标签: java string character-encoding pool

我正在读取二进制文件,并希望将字节转换为US ASCII字符串。有没有办法在new上调用String来避免在字符串文字池中创建多个语义上相等的String对象?我认为这可能是不可能的,因为这里不可能使用双引号引入String个对象。这是对的吗?

private String nextString(DataInputStream dis, int size)
throws IOException
{
  byte[] bytesHolder = new byte[size];
  dis.read(bytesHolder);
  return new String(bytesHolder, Charset.forName("US-ASCII")).trim();

3 个答案:

答案 0 :(得分:2)

您可以在字符串上调用intern()方法,以确保整个JVM的方法。

String s = new String(bytes, "US-ASCII").intern();

您不会再避免再次创建初始字符串,但您将节省存储空间。

话虽如此,实习字符串的存储空间有限,因此请谨慎使用。一个更好的选择可能是使用字符串作为键和值来实现HashMap,并检查字符串是否已经存在并且如果它已经存在则获取它,如果不存在则插入它。这样你就不会有这样的内存限制。

答案 1 :(得分:2)

您必须将字节数组缓存映射到字符串,然后在创建新字符串之前在缓存中搜索任何相等的值。

你可以像Yishai发布的那样用intern()实习现有的字符串 - 这不会阻止你从创建更多的字符串,但它会创造除第一个之外的所有字符串(对于任何字符)序列)非常短暂。另一方面,它会使所有不同的琴弦确实存在很长时间。

您可以使用Map<String, String>

进行“伪实习”
String tmp = new String(bytesHolder, Charset.forName("US-ASCII")).trim();
String cached = cache.get(tmp);
if (cached == null)
{
    cached = tmp;
    cache.put(tmp, tmp);
}
return cached;

你甚至可以投入更多精力并最终使用LRU缓存,这样它就能保留N个最近获取的字符串,并在需要时丢弃其他字符串。

正如我所说,这些都没有减少首先创建的字符串数量 - 但这可能是你情况下的一个问题吗? GC已经过调整,可以非常便宜地创建短期物体。

答案 2 :(得分:1)

您不应该担心它 - 除非您对应用程序进行了概要分析,并确定String创建是您问题的确切来源。

如果您发现String创建 是您问题的根源,我会推荐Jon Skeet建议的内容,即从byte[]到{String的映射{1}}。这与interning String的效果大致相同,但在重新启动VM之前不会占用宝贵的内存。