Java经典语法系列
设计初衷
用过java的同学知道,大部分数据操作基本上是字符串(String)类型的。 比如我们设计表字段时,varchar类型字段居多。
设计HashMap的Key时基本上都是字符串类型。
我们知道如果字符串存储都放在堆(Heap)内存的话,频繁的字符串读写会导致GC压力巨大,程序的性能也会因此大打折扣。基于此,Java建立字符串类型的 字符串池 就势在必行了。
字符串池(String Pool)
Java虚拟机( JVM )为了提升程序的性能以及减少内存开销,避免字符串实例的重复创建,JVM会在 堆内存 中开辟了一块特殊的内存空间,即字符串池(String Pool)。
字符串池由String类私有维护。
字符串常量 (String Constant)
字符串池中的每个字符串实例只存在唯一一份。
字符串池原理
看过String源码的同学知道,String的类是final类型的。
核心V数组变量也是final类型的。
为什么要String要设计成final类型呢?我们先来看看final关键字的特性。
final关键字
由《 》文章得出final关键字的两个特性:
- 被final修饰的类不能被子类继承
- 被final修饰的字段值不可修改
而这个两个特性恰恰是设计字符串池的关键所在,也是设计字符串池三个特性的理论基础。
一、字符串的不可继承性
被final修饰的类不能被继承,即它不能拥有自己的子类,这样就防止其他类修改final类的成员变量值。
二、字符串的不可变性
我们知道被final修饰的变量是不可更改的,但其真正含义是 引用地址不能改变。
比如我们定义一个Int类型长度为3的数组,就不能再用ints变量指向一个Int类型长度为4的数组呢。
但是我们可以修改数组内部元素的值。
我们发现数组下标为2的值从2变成3,说明数组内部元素值是可以修改的。
那字符串是怎么解决这个问题的呢?
我们看看String内部源码可知: 发现String的内部成员变量都是私有类型(private) 。
我们知道 如果一个类的成员变量是私有的,那意味着该变量的访问权限只限于本类中,对子类和其他类不可见,这样就防止外部类修改其成员变量值 。
final的不可变性加上变量私有访问权限,从而保证了字符串的不可变性。
三、字符串的线程安全性
由于字符串是不可变的,这里包含两层含义:
第一,字符串常量初始化时会立即更新到主内存~ 写操作
第二,多线程从主内存读取字符串常量~ 读操作
所以我们说字符串是线程安全的。
字符串 初始化 方式
1)采用变量赋值
String str1 = "abc" String str2 = "abc"
2)采用new关键字新建一个字符串对象。
String str1 = new String("abc") String str2 = new String("abc")
这两种方式有什么差别呢?
编译期
采用变量赋值方式,其在编译期存储到字符串池里。所以用双引号“”赋值,str1和str2引用地址都是指向字符串常量“abc”;
str1 == str2 为true
运行期
采用new的方式是直接在堆内存开辟两块空间存储String对象。用str1和str2两个引用地址指向这个两块堆内存空间,所以str1 == str2为假。
str1 == str2 为 false
String赋值变种
1、字符串 “+” 连接符
String s = "11" + "22"
s创建的是字符串常量,属于编译期变量赋值方式,在字符串池值为“1122”。而像”11″,”22″,不会在字符串池创建。
2、包含变量的字符串”+” 连接符组合方式
String s1 = "11" String s2 = "22" + s1
s2 = “22” + s1创建的对象是运行期才创建的,存储在堆中。
java规定
只要s1是变量,不论s1指向池中的字符串常量还是堆中的字符串对象,运行期s1 + “22”操作实际上是编译器创建了 StringBuilder 对象进行了 append 操作后通过toString()返回了一个字符串对象存在堆上。
3、多变量赋值”+” 连接符组合方式
String s1 = "11" String s2 = "22" + s1 String s3 = "22" + s1
虽然s2,s3都包含变量s1并且指向s1 + “22”。但是却指向两个不同的对象,本质是s2/s3在堆上new出了两个StringBuilder对象来进行append操作。
4、final修饰的变量
final String s1 = "11" String s2 = "22" + s1
s1被用final修饰,属于编译期变量赋值方式。所以“22” + s1等同于 “22” +“11”,也属于编译期变量赋值方式。
关于我
我是Wooola,擅长微服务,分布式,并发,工作流。请您多多关注我的头条号,我会持续更新干货给大家。
有需要Java资料的同学,可以关注之后私信哈,回复“资料”可以免费领取Java BAT面试宝典/微服务/SpringCloud/SpringBoot等视频和资料,亲记得要点赞转发哦!!!