5

我正在从二进制文件中读取并希望将字节转换为美国 ASCII 字符串。有没有办法做到这一点而不调用newString避免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();
4

3 回答 3

3

您可以在字符串上调用 intern() 方法以确保为整个 JVM 提供一个方法。

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

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

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

于 2009-10-16T14:33:19.647 回答
3

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

您可以使用 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 已经过调整,可以非常便宜地创建短期对象。

于 2009-10-16T14:37:06.240 回答
2

您不应该担心它——除非您分析了您的应用程序并确定String创建是您问题的确切来源。

如果您发现String创建您问题的根源,我会推荐Jon Skeet提出的建议,即从byte[]到的映射String。这与在重新启动 VM 之前不占用宝贵内存的情况下实习的效果大致相同。String

于 2009-10-16T15:15:33.213 回答