1、String底层 

底层是一个不可变字符串,使用连接符的时候,实际上是经过了StringBuilder的优化处理的,并不是在原来的String对象中做追加,

最后再调用toString()方法,是把当前StringBuilder的对象变成了String

1.1 StringJDK1.8中的底层实现,如下:

private final char value[];

1.2 StringJDK1.9中的底层实现,如下:

@Stable //表示下方属性 最多被赋值1次!
private final byte[] value;

1.3 char数组换为byte数组的原因

开发者发现人们在使用字符串的时候,多数使用的是拉丁文,而拉丁文所占字节数为1

JDK1.8底层实现是使用的char数组,一个char类型所占字节数为2,所以在char数组存储拉丁文的时候浪费了一个字节的内存空间。

所以开发者在JDK1.9char数组改为了byte数组!

 

2、创建与内存场景分析

String s1 = "abc";

分析:对于常量赋值,变量s1始终指向了字符串常量池的字符串(只有一份)

String s1 = new String("abc");

分析:生成了两个对象,分别是“abc” 和  new String("abc")“abc”在类加载的时就已经创建

“abc” 是存在于常量池中 ,而s1指向堆里的对象。

String s1 = "a" + "b"; 

分析:当一个字符串由多个字符串常量连接而成时,该字符串是在编译期就能确定。先是在池里生成“a”“b”,再通过拼接的方式生成"ab" 

String s1 = new String("a") + new String("b");

分析: 这句话一共生成了5个对象,首先会先在池子生成“a”“b”,然后会在堆里生成对象new String("a")new String("b)

这两个对象分别指向常量池的所对应的字符串,接着由于“+”的作用下,创建了新的对象,这个对象通过利用之前的对象所指向的字符进行拼接生成“ab”

注意:+操作是在堆里实现的,不会将生成的"ab"放在常量池里,此时之前的两个对象已经没有作用了,需要等待垃圾回收。

String intern()方法

String s1 = new String("a");
String s2 = s1.intern();
Systrm.out.println(s1 == s2); // false
  

先在池里创建“a”,返回一个对象引用赋给堆里的对象new String("a"),也就s1所指向的地方。

通过调用 intern() 方法,在池里找到s1对象所对应的字符串,并且进行返回给s2对象,所以s2所指向的地方,在常量池里。

  

3、汉字是如何存储的

String类将字符存储在char数组中,每个字符使用两个字节(16位)。

疑问:为什么有时候getBytes() 获得的byte数组是一个汉字长度为3

Strings="你";
byte[]a=s.getBytes();
System.out.println(a.length);

解答:java采用unicode2个字节来表示一个字符。"你"这个中文字符的unicode就是2个字节。

String.getBytes(encoding)方法是获取指定编码的byte数组表示,通常gbk/gb23122个字节,utf-83个字节。

注意:Windows 系统:getBytes() 用的是 Windows 的默认编码 GB18030,那1个汉字会被拆成2个字节

Linux 或者 macOS 系统:getBytes() 默认编码是UTF-8,那1个汉字会被拆成3个字节

如果想在各平台上拆成相同的字节,那需要使用 getBytes( "GBK" )

 

 

博客借鉴https://www.cnblogs.com/liangyueyuan/p/9796992.html

posted on 2021-10-19 20:17  smile学子  阅读(299)  评论(0)    收藏  举报