当前位置: 首页 > news >正文

Java SE 学习哈希表后对String的讨论

1.发现问题

我们在学习String后,知道它常用的构造方法分别为以下三种:

1.使用常量字符串直接构造,比如:

String s1 = "hello";

2.通过new String对象构造,比如:

String s2 = new String("hello");

3.使用字符数组构造,比如:

char[] ch = {'h','e','l','l','o'};
String s3 = new String(ch);

不仅如此,我们还知道String的字符串是储存在String类中的一个数组中,并且这个数组是私有的,无法直接对它进行操作,这也就是String的不可变性的由来。知道了String是怎么保存字符串之后,难免会产生一个疑问:String作为Java中经常使用的引用类型,创建String对象时,它是直接通过构造方法创建的,还是有别的方法。

请看下面的代码:

public class Test {public static void main(String[] args) {String s1 = "hello";String s2 = "hello";String s3 = new String("hello");String s4 = new String("hello");System.out.println(s1 == s2);System.out.println(s3 == s4);System.out.println(s1 == s3);}
}//运行结果:
true
false
false

发现:s1和s2引用的是同一个对象,而s3和s4引用的不是同一个对象。为什么会造成这种原因呢?这就不得不引入一个新的概念了——“”。

2.“池”是什么东西?

“池”(Pool)的核心逻辑就是提前准备好一批常用资源,谁要用就直接拿,用完了还回来,避免反复创建和销毁,就像生活里的 “共享工具站”,它是编程中的一种常见的, 重要的提升效率的方式, 有各种各样的池,比如说: "内存池", "线程池", "数据库连接池" ……

在Java程序中,类似于:1,2,3.14,"hello"等字面类型(指的是在代码中直接写出的、代表固定值的 “字面量”,它是数据的直接表示形式,无需计算或引用其他变量就能确定值)的常量经常频繁使用,为了使程序的运行速度更快、更节省内存,Java为8种基本数据类型和String类都提供了常量池。为了节省存储空间以及程序的运行效率,Java中引入了:

  • Class文件常量池:每个.Java源文件编译后生成.Class文件中会保存当前类中的字面常量以及符号信息。
  • 运行时常量池:在.Class文件被加载时,.Class文件中的常量池被加载到内存中称为运行时常量池,每个类都有一份运行时常量池
  • 字符串常量池:String 常量池是 JVM 内存中一块特殊的区域(在 JDK 7 及之后位于堆内存,之前位于方法区),专门用于存储字符串常量(即编译期确定的字符串,如直接写在代码中的"abc")。

3.关于字符串常量池(StringTable)

在Java的JVM中字符串常量池是StringTable类,这个类实际是一个固定大小的哈希表(HashTable),在不同JDK版本下字符串常量池的位置以及默认大小是不同的,比如说:

JDK版本字符串常量池位置大小设置
Java6(方法区)永久代固定大小:1009
Java7堆中可设置,没有大小限制,默认大小:60013
Java8堆中可设置,有范围限制,最小是1009

4.再次探讨创建String对象

开头,我们说Java中String对象的创建使用的构造方法通常有三种,但是它们真的都是构造方法么,其实第一种方式,即使用常量字符串直接构造,这种方式严格意义上不能算做一种构造方法,因为构造方法的调用必须通过 new 关键字触发。现在我们结合字符串常量池来分析一下三种构造方法的底层实现。在开始前。再次明确“池”的核心逻辑:

提前准备好一批常用资源,谁要用就直接拿,用完了还回来,避免反复创建和销毁。

1.使用常量字符串直接构造

当我们通过这种方式创建String对象时,比如说 String s1 = "abc",此时JVM会先去字符串常量池中查找是否有"abc"这个String对象,如果有,那么令s1直接指向这个已有的对象(不会创建新的String对象);如果没有,在常量池中创建String对象("abc"),再让s1引用它(仅创建一次),同时字符串常量池保存这个对象,方便之后复用。

注:在字符串常量池中创建String对象并不依赖于String类的构造方法,它依赖的是JVM的底层操作——直接在常量池区域分配内存并初始化(底层是数组)。同时得益于String的不可变性,使得字符串常量池可以实现“多个引用共用一个对象”!一旦字符串对象存入常量池,其内容就永远不会被修改,因此复用是安全的。画图举例如下:

2.通过new创建String对象

通过new创建String对象,这里主要讨论开头所说的常用方法的两种。

2.1 通过new String对象构造

当我们通过像:String s3 = new String("hello");这样的方式创建String对象时,创建的过程是这样的:JVM会先去字符串常量池查找是否存在“hello”这个String对象,如果没有就在字符串常量池中创建String对象("hello"),接着获取储存"hello"数组的引用;如果有,就直接获取"hello"数组的引用。接着按照构造方法String(String original)在堆中创建一个String对象,并且令这个String对象的value指向获取的"hello"的数组,这就实现了String对象的创建。

需要注意的是:局部变量s3引用的是堆中新建的String对象,而这个String对象的value指向的是字符串常量池中"hello"String对象的value所指向数组。

具体过程如图所示:

2.2 使用字符数组构造

对于使用字符数组构造的方式来创建String对象的方式,它与上述两种方式有明显的区别,它的具体过程是这样的:调用String(char[] value)构造方法,直接在堆中创建新对象,这个新对象的value指向的是传入数组value的副本,这种方式不主动关联常量池。图示如下:

假设说我们现在通过字符数组创建String对象了,那么也没有办法把这个String对象添加到字符串常量池方便我们以后使用呢?其实是有的!就是intern方法,intern 是一个native方法(Native方法指:底层使用C++实现的,因此看不到其实现的源代码),该方法的作用是手动将创建的String对象添加到常量池中。像这样使用:

public class Test {public static void main(String[] args) {char[] ch = {'a','b','c'};String s1 = new String(ch);s1.intern();         //将s1这个对象放入字符串常量池中String s2 = "abc";   //创建s2时,发现字符串常量池中有"abc"这个对象,//那么s2直接指向这个对像                                                                                                          System.out.println(s1 == s2);}
}//运行结果:
true

根据运行结果,发现s1与s2引用的是同一个对象,说明s1放入字符串之后,创建s2时,在字符串常量池中查找到"abc"这个对象,那么直接令s2指向这个对象。

5.总结

字符串常量池遵循着“池”的核心逻辑:提前准备好一批常用资源,谁要用就直接拿,用完了还回来,避免反复创建和销毁。当我们创建一个String对象时,JVM会先去字符串常量池查找是否有创建String对象的字符串,如果有,那么直接令String引用指向字符串常量池中的对象或者令String引用的String对象的value字段指向字符串常量池中的对象的value所指向的数组即可;没有再考虑创建新的String对象。简单来说,字符串常量池主要实现了以下关键作用:

  1. 字符串对象的复用
  2. 提高代码的执行效率
  3. 保障字符串不可变性的安全复用。

  4. 跨类全局共享。字符串常量池是 JVM 级别的全局资源(全进程共享),不同类、不同方法中声明的相同字符串,都能复用同一个常量池对象,实现了字符串资源的全局优化。

到此,本篇文章结束,感谢您的阅读,如有不对,还请指出!谢谢!

http://www.dtcms.com/a/561978.html

相关文章:

  • 烟台网站制作建设wordpress首页出现恶意链接
  • Linux C/C++ 学习日记(46):io_uring(二):reactor 与proactor的性能测试对比
  • 如何在 Linux 中创建自签名 SSL 证书 ?
  • 安阳做网站公司亚马逊关联乱码店铺怎么处理
  • 网站设计公司发展网站美工培训课程
  • 响应式网站是个坑优秀网页设计网址
  • 如何做聊天网站变更icp备案网站信息查询
  • 机器学习20:自编码器(Auto-Encoder)与扩散模型综述学习
  • Spring Boot解决循环依赖的几种办法
  • 成品网站免费网站下载外贸网站建设 广州
  • 网站开发费用结算wordpress 开发搜索框
  • 网站视觉规范不需要备案如何做网站
  • langchain基础
  • vue2+vuex登录功能
  • fastapi -- 耗时任务处理
  • 网站建设咨询服务企业级服务器配置
  • 做阅读任务挣钱的网站北京网站建设公司哪家最好
  • 零基础学Python_自动补全符号
  • C++14 新特性:更加简洁和高效的编程体验
  • 邹城网站设计百中搜
  • 青海省住房和城乡建设厅官方网站wordpress s.w.org
  • Apollo Planning 模块技术深度解析
  • 哪个网站可以帮助做数学题百度推送
  • 企业网站和信息化建设哪里有网站制作服务
  • 【Linux】深入理解进程(三)(环境变量)
  • 【C学生序号姓名学号年龄降序排序】2022-12-9
  • 平衡二叉树解题思路
  • 电子商务网站应该如何建设四川教育公共信息服务平台
  • 响应式官方网站便宜自适应网站建设厂家
  • 实例016 百元买百鸡问题