Java 11 的String是如何优化存储的?

简介: 本文介绍了Java中字符串存储优化的原理和实现。通过判断字符串是否全为拉丁字符,使用`byte`代替`char`存储,以节省空间。具体实现涉及`compress`和`toBytes`方法,前者用于尝试压缩字符串,后者则按常规方式存储。代码示例展示了如何根据配置决定使用哪种存储方式。

优化的依据是什么?

Java 中的 char 是两个byte大小,因为我们大多数的时候操作数据都是都是用拉丁语系的字符的,而拉丁语系的字符只要用byte就足够存储了,根本就不需要char。所以如果我们发现发现了一个字符串里只有拉丁语系的字符,那么我们全都用byte,这样就比原来的用char来存储节省一半的存储空间了。

具体实现思想是什么?

判断一个字符串里是否都是拉丁语系的字符,如果全都是,那么OK,一个char用一个byte来代替就行,存储就是简单的一个直接截取char的起始八位就行。

代码实现

String 中的代码:

  • 先判断是否开启了字段压缩机制是否开启,默认是开启的
  • 如果开启了,就用 StringUTF16.compress(value, off, len);来压缩,需要判断是否压缩成功,因为我们无法事先知道字符串里是否都是拉丁语系的字符组成的。
  • 如果没有开启,那就用StringUTF16.toBytes(value, off, len);就是默认都用utf-16来处理,这样其实就没有达到节省空间的目的了。

代码解读

复制代码

static final boolean COMPACT_STRINGS;

static {
    COMPACT_STRINGS = true;
}
public String(char value[]) {
    this(value, 0, value.length, null);
}
String(char[] value, int off, int len, Void sig) {
    if (len == 0) {
        this.value = "".value;
        this.coder = "".coder;
        return;
    }
    if (COMPACT_STRINGS) {
        byte[] val = StringUTF16.compress(value, off, len);
        if (val != null) {
            this.value = val;
            this.coder = LATIN1;
            return;
        }
    }
    this.coder = UTF16;
    this.value = StringUTF16.toBytes(value, off, len);
}

再来看看几个关键的方法:compresstoBytes

  • compress方法,逐个遍历字符,如发现字符的对应的数字大于0xFF,那么就退出,毫无疑问,就代表着这个不是拉丁字符系的,那么就退出了,且返回0; 如果都是拉丁语系的,那么就都用byte来保存
  • toBytes就是代表着用两个byte来保存char数据了,就没有起到节省空间的目的。

代码解读

复制代码

private static native boolean isBigEndian();

static final int HI_BYTE_SHIFT;
static final int LO_BYTE_SHIFT;
static {
    if (isBigEndian()) {
        HI_BYTE_SHIFT = 8;
        LO_BYTE_SHIFT = 0;
    } else {
        HI_BYTE_SHIFT = 0;
        LO_BYTE_SHIFT = 8;
    }
}
// 如果返回的长度不等于len,那么就要返回null,就说明有非拉丁语系的字符存在。
 public static byte[] compress(char[] val, int off, int len) {
     byte[] ret = new byte[len];
     if (compress(val, off, ret, 0, len) == len) {
    	return ret;
     }
     return null;
 }
// compressedCopy char[] -> byte[]
//逐个遍历字符,如发现字符的对应的数字大于`0xFF`,那么就退出,毫无疑问,就代表着这个不是拉丁字符系的,那么就退出了。

@HotSpotIntrinsicCandidate
public static int compress(char[] src, int srcOff, byte[] dst, int dstOff, int len) {
	for (int i = 0; i < len; i++) {
		char c = src[srcOff];
		if (c > 0xFF) {
			len = 0;
			break;
		}
		dst[dstOff] = (byte)c;
		srcOff++;
		dstOff++;
	}
	return len;
}
// 其实如果用了这个方法,其实就达不到节省空间的目的了,也就意味着,其中有个非拉丁字符,
// 每个字符都要转成两个byte来存储。
@HotSpotIntrinsicCandidate
public static byte[] toBytes(char[] value, int off, int len) {
	byte[] val = newBytesFor(len);
	for (int i = 0; i < len; i++) {
		putChar(val, i, value[off]);
		off++;
	}
	return val;
}

@HotSpotIntrinsicCandidate
// intrinsic performs no bounds checks
static void putChar(byte[] val, int index, int c) {
	assert index >= 0 && index < length(val) : "Trusted caller missed bounds check";
	index <<= 1;
	// 移位,然后直接硬转,直接截取低八位。
	val[index++] = (byte)(c >> HI_BYTE_SHIFT);
	val[index]   = (byte)(c >> LO_BYTE_SHIFT);
}


转载来源:https://juejin.cn/post/6844904002325331981

相关文章
|
23天前
|
监控 算法 Java
Java虚拟机(JVM)垃圾回收机制深度剖析与优化策略####
本文作为一篇技术性文章,深入探讨了Java虚拟机(JVM)中垃圾回收的工作原理,详细分析了标记-清除、复制算法、标记-压缩及分代收集等主流垃圾回收算法的特点和适用场景。通过实际案例,展示了不同GC(Garbage Collector)算法在应用中的表现差异,并针对大型应用提出了一系列优化策略,包括选择合适的GC算法、调整堆内存大小、并行与并发GC调优等,旨在帮助开发者更好地理解和优化Java应用的性能。 ####
30 0
|
16天前
|
存储 JavaScript Java
Java 中的 String Pool 简介
本文介绍了 Java 中 String 对象及其存储机制 String Pool 的基本概念,包括字符串引用、构造方法中的内存分配、字符串文字与对象的区别、手工引用、垃圾清理、性能优化,以及 Java 9 中的压缩字符串特性。文章详细解析了 String 对象的初始化、内存使用及优化方法,帮助开发者更好地理解和使用 Java 中的字符串。
Java 中的 String Pool 简介
|
2天前
|
缓存 算法 搜索推荐
Java中的算法优化与复杂度分析
在Java开发中,理解和优化算法的时间复杂度和空间复杂度是提升程序性能的关键。通过合理选择数据结构、避免重复计算、应用分治法等策略,可以显著提高算法效率。在实际开发中,应该根据具体需求和场景,选择合适的优化方法,从而编写出高效、可靠的代码。
15 6
|
21天前
|
缓存 安全 Java
java 为什么 String 在 java 中是不可变的?
本文探讨了Java中String为何设计为不可变类型,从字符串池的高效利用、哈希码缓存、支持其他对象的安全使用、增强安全性以及线程安全等方面阐述了不可变性的优势。文中还通过具体代码示例解释了这些优点的实际应用。
java 为什么 String 在 java 中是不可变的?
|
24天前
|
存储 监控 小程序
Java中的线程池优化实践####
本文深入探讨了Java中线程池的工作原理,分析了常见的线程池类型及其适用场景,并通过实际案例展示了如何根据应用需求进行线程池的优化配置。文章首先介绍了线程池的基本概念和核心参数,随后详细阐述了几种常见的线程池实现(如FixedThreadPool、CachedThreadPool、ScheduledThreadPool等)的特点及使用场景。接着,通过一个电商系统订单处理的实际案例,分析了线程池参数设置不当导致的性能问题,并提出了相应的优化策略。最终,总结了线程池优化的最佳实践,旨在帮助开发者更好地利用Java线程池提升应用性能和稳定性。 ####
|
25天前
|
存储 算法 Java
Java 内存管理与优化:掌控堆与栈,雕琢高效代码
Java内存管理与优化是提升程序性能的关键。掌握堆与栈的运作机制,学习如何有效管理内存资源,雕琢出更加高效的代码,是每个Java开发者必备的技能。
49 5
|
23天前
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
26天前
|
存储 缓存 安全
Java 集合框架优化:从基础到高级应用
《Java集合框架优化:从基础到高级应用》深入解析Java集合框架的核心原理与优化技巧,涵盖列表、集合、映射等常用数据结构,结合实际案例,指导开发者高效使用和优化Java集合。
36 4
|
1月前
|
监控 算法 Java
Java虚拟机垃圾回收机制深度剖析与优化策略####
【10月更文挑战第21天】 本文旨在深入探讨Java虚拟机(JVM)中的垃圾回收机制,揭示其工作原理、常见算法及参数调优技巧。通过案例分析,展示如何根据应用特性调整GC策略,以提升Java应用的性能和稳定性,为开发者提供实战中的优化指南。 ####
41 5