Java中的String

首先String不属于8种基本数据类型,String是一种引用数据类型,其默认值是null。
String类在Java中是一个不可变类,字符串在被创建后不能被更改。

这是Java中String类的部分源码

通过上图,我们可以得出:
1)String类被final关键字修饰,意味着String类不能被继承;字符串一旦创建就不能再修改。
2)String类实现了Serializable、CharSequence、 Comparable接口。
3)String实例的值是通过字符数组实现字符串存储的。

通过源码,我们也就可以知道为什么String类不可变:
1、底层char[]数组有final修饰,意味着这个数组不能扩容等,来达到存更多的字符。
2、char[]数组是私有的,程序员无法直接操作这个char[]数组,而且String没有提供这样的方法,来修改char[]数组的元素的值。
3、String提供的所有的方法,对字符串的修改都是给你返回一个新的字符串对象。

字符串对象底层的存储:
JDK1.9之前:底层是用 char[ ] 存储
JDK1.9之后:底层选用 byte[ ] 存储

虚拟机内存主要分为三块:
堆:存放对象实例和数组。
栈:存放基本类型,以及对象的引用。
方法区:“类”被加载后的信息,常量、静态变量存放在这儿。

在Java的内存分配中,总共3种常量池,分别是Class常量池、运行时常量池、字符串常量池。
字符串的分配和其他对象分配一样,是需要消耗高昂的时间和空间的,而且字符串使用的非常多。JVM为了提高性能和减少内存的开销,在实例化字符串的时候进行了一些优化:使用字符串常量池。每当创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就直接返回常量池中的实例引用。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。由于String字符串的不可变性,常量池中一定不存在两个相同的字符串。

字符串常量池在哪里?(Oracle官方虚拟机HotSpot)
(1)JDK1.6以及之前:方法区中
(2)JDK1.7:挪到堆中,即在堆中单独划分了一块字符串常量
(3)JDK1.8:从堆中挪出,挪到一个 “元空间meta space”,即类似于方法区

字符串常量池(String Pool)是方法区中的一块存储空间,当创建一个字符串时,如果池中已经存在相同的字符串就会返回其引用,而不是在堆中创建一个新对象。(此处指的是字面量创建字符串,用new关键字创建的话,无论池中存不存在都会在堆中创建一个新对象)

字符串常量池:
  1、当直接创建一个字符串时,变量会到字符串常量池中去寻找该字符串,如果找到了,该变量指向该字符串;如果没有找到,会用 byte[ ]拼接成所需的字符串,然后放入常量池中并指向它。
  2、使用 new 关键字创建字符串,会在堆区创建一个 String 对象,而且底层是用 byte[ ] 数组拼接的,这个 String 对象并没有放入字符串常量池中,而是在堆中,该变量指向该对象的地址。

字符串的拼接

字符串对象可以使用“+”连接其他对象。其中字符串连接是通过 StringBuilder(或 StringBuffer)类及其append 方法实现的,对象转换为字符串是通过 toString方法实现的,该方法由 Object 类定义,并可被 Java 中的所有类继承。

使用“+”连接符时,JVM会隐式创建StringBuilder对象,这种方式在大部分情况下并不会造成效率的损失,不过在进行大量循环拼接字符串时则需要注意。

这样由于大量StringBuilder创建在堆内存中,肯定会造成效率的损失,所以在这种情况下建议在循环体外创建一个StringBuilder对象调用append()方法手动拼接。

与此之外还有一种特殊情况,也就是当"+"两端均为编译期确定的字符串常量时,编译器会进行相应的优化,直接将两个字符串常量拼接好。

拼接的注意事项:
1、常量与常量的拼接结果在常量池中
2、只要其中有一个是变量,结果就在堆中
3、如果拼接的结果调用 intern() 方法,就在常量池中

intern方法

直接使用双引号声明出来的String对象会直接存储在字符串常量池中,如果不是用双引号声明的String对象,可以使用String提供的intern方法。intern 方法是一个native方法,intern方法会从字符串常量池中查询当前字符串是否存在,如果存在,就直接返回当前字符串;如果不存在就会将当前字符串放入常量池中,之后再返回。

参考资料

https://blog.csdn.net/liyu4352502/article/details/100772926
https://www.cnblogs.com/niujifei/p/11303420.html
https://blog.csdn.net/ifwinds/article/details/80849184

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 这里来对Java中的String对象做一个稍微深入的了解。 Java对象实现的演进 String对象是Java中使...
    也许会了阅读 1,219评论 0 9
  • Java中的string类型一直是一个热点问题,也是Java面试问题中的常客。string类型涉及到常量池,堆等方...
    柳蒿阅读 120评论 0 0
  • 第一,简介 String是java语言非常基础和重要的类,提供了构造和管理字符串的各种基本逻辑。它是典型的immu...
    温驭臣阅读 524评论 0 0
  • String本质上是一个字符数组; 构造方法 String有很多构造方法,这边只介绍几个: String(Stri...
    DeeJay_Y阅读 515评论 0 0
  • 在描述理论之前,我们先看段代码: 各位读者可以先按照自己的理解想一下代码中等式的结果,看看最后的结果是不是一样。如...
    唐T唐X阅读 1,011评论 3 2