Java关于字符串的优化学习

2023年 7月 14日 57.3k 0

String 对象是我们使用最频繁的一个对象类型,但它的性能问题却是最容易被忽略的。String 对象作为 Java 语言中重要的数据类型,是内存中占据空间最大的一个对象。高效地使用字符串,可以提升系统的整体性能。

String 存储变化

随着 Java 版本的更迭,工程师们对 String 对象做了大量的优化,来节省存储空间。

1、在 Java6 以及之前的版本中,String 对象是对 char 数组进行了封装实现的对象,主要有四个成员变量:char 数组、偏移量 offset、字符数量 count、哈希值 hash。String 对象是通过 offset 和 count 两个属性来定位 char[]数组,获取字符串。这么做可以高效、快速地共享数组对象,同时节省内存空间,但这种方式很有可能会导致内存泄漏。

public final class String
  implements java.io.Serializable, Comparable, CharSequence
{
  /** The value is used for character storage. */
  private final char value[];

  /** The offset is the first index of the storage that is used. */
  private final int offset;

  /** The count is the number of characters in the String. */
  private final int count;

  /** Cache the hash code for the string */
  private int hash; // Default to 0
  ...
}

2、 从 Java7 版本开始到 Java8 版本,Java 对 String 类做了一些改变。String 类中不再有 offset 和 count 两个变量了。这样的好处是 String 对象占用的内存稍微少了些,同时,String.substring 方法也不再共享 char[],从而解决了使用该方法可能导致的内存泄漏问题。

public final class String
  implements java.io.Serializable, Comparable, CharSequence {
  private final char value[];

  /** Cache the hash code for the string */
  private int hash; // Default to 0

  .....
}

3、从 Java9 版本开始,工程师将 char[]字段改为了 byte[]字段,又维护了一个新的属性 coder,它是一个编码格式的标识。

public final class String
  implements java.io.Serializable, Comparable, CharSequence {
  @Stable
  private final byte[] value;

  private final byte coder;

  /** Cache the hash code for the string */
  private int hash; // Default to 0
  
  .....
}

至于为何要这样改?我们知道一个 char 字符占 16 位,2 个字节。这个情况下,存储单字节编码内的字符(占一个字节的字符)就显得非常浪费。JDK1.9 的 String 类为了节约内存空间,于是使用了占 8 位,1 个字节的 byte 数组来存放字符串。

而新属性 coder 的作用是,在计算字符串长度或者使用 toCharArray()函数时,我们需要根据这个字段,判断如何计算字符串长度。coder 属性默认有 0 和 1 两个值,0 代表 Latin-1(单字节编码),1 代表 UTF-16。如果 String 判断字符串只包含了 Latin-1,则 coder 属性值为 0,反之则为 1。

public char[] toCharArray() {
  return isLatin1() ? StringLatin1.toChars(value)
    : StringUTF16.toChars(value);
}

private boolean isLatin1() {
  return COMPACT_STRINGS && coder == LATIN1;
}

static final byte LATIN1 = 0;
static final byte UTF16  = 1;

以前学习 String 源码时,只关注了 JDK8 的源码,对于 JDK9 的改动没有了解,既然把 char[] 改为了 byte[] 数组,那么我第一时间就想去了解 String 是如何存储汉字的?

关于这部分内容可以参考网友的这篇文章《Java中如何存储汉字》,通俗易懂。

String学习

关于字符串的优化,首先需要学习字符串常量池和 String 源码,在此基础上,非常容易理解字符串的优化。

这里推荐几篇我之前写的文章:

Java 中方法区与常量池

Java 基础:String 类源码分析

Java 基础:String——常量池与 intern

String优化

1、构建超长字符串

String str = "abcdef";

for(int i=0; i

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论