字符串字符串的示例分析

  

这篇文章主要介绍String字符串的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

实现原理

在 Java6 以及之前的版本中,String 对象是对 char 数组进行了封装实现的对象,主要有四个成员变量:char 数组、偏移量 offset、字符数量 count、哈希值 hash。

从 Java7 版本开始到 Java8 版本,String 类中不再有 offset 和 count 两个变量了。这样的好处是 String 对象占用的内存稍微少了些。

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

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

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

不可变

查看String类的代码可以发现,String类被final关键字修饰,因此这个类不能被继承,并且String类里面的变量char 数组也被 final 修饰了,因此String对象不能被修改。

String对象不可变主要有如下几个优点:

第一,保证 String 对象的安全性。假设 String 对象是可变的,那么 String 对象将可能被恶意修改。

第二,保证 hash 属性值不会频繁变更,确保了唯一性,使得类似 HashMap 容器才能实现相应的 key-value 缓存功能。

第三,可以实现字符串常量池。

在 Java 中,通常有两种创建字符串对象的方式:

第一种是通过字符串常量的方式创建,如String str="abc"

第二种是字符串变量通过new 形式的创建,如 String str=new String("abc")

当代码中使用第一种方式创建字符串对象时,在编译类文件时,”abc”常量字符串将会放入到常量结构中,在类加载时,“abc”将会在常量池中创建;然后,str将引用常量池中的字符串对象。这种方式可以减少同一个值的字符串对象的重复创建,节约内存。

String str=new String("abc") 这种方式,首先在编译类文件时,”abc”常量字符串将会放入到常量结构中,在类加载时,“abc”将会在常量池中创建;其次,在调用new时,JVM 命令将会调用 String 的构造函数,String 对象中的 char 数组将会引用常量池中”abc”字符串的char 数组,在堆内存中创建一个 String 对象;最后,str 将引用 String 对象,String对象的引用跟常量池中”abc”字符串的引用是不一样的。

对象与引用:对象的内容存储在内存中,操作系统通过内存地址来找到存储的内容,引用就是指内存的地址。

比如:String str=new String("abc"),变量str指向的是String对象的存储地址,也就是说 str 并不是对象,而只是一个对象引用。

字符串拼接

常量相加

String str = "ab" + "cd" + "ef";

查看编译后的字节码

0 ldc #2 2 astore_13 return

可以发现编译器将代码优化成如下所示

String str= "abcdef";

变量相加

String a = "ab";String b = "cd";String c = a + b;

查看编译后的字节码

 0 ldc #2 
  ,2 astore_1  3, ldc  # 3, & lt; cd>
  ,5 astore_2  6, new  # 4, & lt; java/lang/StringBuilder>
  null

字符串字符串的示例分析