摘要:方法就是扩充常量池的一个方法当一个实例调用方法时,会查找当前常量池中是否已有相同的字符串常量,如果有就返回其引用,如果没有就在常量池中添加对应的字符串,并返回对应字符串常量的引用。
常量池:在编译被确定,并保存在.class文件中的一些数据。jvm为每个类维护一个常量池,常量池就是该类型所用到的常量的一个有序集合。在程序执行的时候,常量池存储在方法区中。存在于.class文件中的常量池,在运行期被jvm装载,并且可以扩充。
String.intern()方法就是扩充常量池的一个方法
当一个string实例调用intern方法时,会查找当前常量池中是否已有相同的字符串常量,如果有就返回其引用,如果没有就在常量池中添加对应的字符串,并返回对应字符串常量的引用。
String str0 = "hello world!"; String str1 = new String("hello world!"); String str2 = "hello" + " world!"; //可确定字符串常量池中有3个string字符串常量 "hello" "world!" "hello world!" Stirng str3 = "hello" + new String("world!"); //常量池1(hello) + 堆2(world + hello world),这是由于String的不可变性所致 System.out.println(str0 == str1); //false System.out.println(str0 == str2); //true System.out.println(str0 == str3); //false str1.intern(); str11 = str1.intern(); //常量池中存在该常量,直接返回其引用 System.out.println(str1 == str11); //false str1在堆中,str11在常量池中 System.out.println(str0 == str11); //true
补充:String的不可变性
//String的实例一旦生成就不会再改变,比如 String str = "he" + "is" + "string";
其中有5个字符串常量:"he", "is", "string", "heis", "heisstring"
因为Stirng 的不可变性产生了很多的临时变量,所以这种情况一般使用StringBuffer或者StringBuider。
jvm优化
jvm会对“+”号连接的字符串常量优化为连接后的值
String str1 = "aaa"; String str2 = "bbb"; String str3 = "aaabbb"; String str4 = "aaa" + "bbb"; String str5 = "aaa" + str2; System.out.println(str3 == str4); //true System.out.println(str3 == str5); //false
对于str5,由于字符串的连接有引用存在,而引用的值在编译期是无法确定的,只有在程序运行的时候动态分配并将其连接后的新引用返回,其实,str3指向常量池,而str5指向堆,所以 str3 == str5 为false
String ab1 = "aaabbb"; final String b = "bbb"; String ab2 = "aaa" + b; System.out.println(ab1 == ab2); //true
final修饰string就可以确保此时b的值不能被改变,所以jvm也可以对其进行优化。所以归纳一句话为:当String连接符两边是不能被改变的,那在编译时jvm就可以进行优化。final使得b只能指向“bbb”,而“bbb”又是在常量区中(常量区中的常量不能被改变),所以b是不能被改变的,如果上例去掉final,那么b就可以指向其他的地方,表明b是可以被改变的,所以jvm在编译时不进行优化。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/64760.html
摘要:注意运行时常量池存在于方法区中。一个在堆中,一个在字符串常量池中。注意,是把这个对象添加到字符串常量池。内存中有一个基本类型封装类的常量池。需要注意的是,和这两个类并没有对应的常量池。 在写之前我们先来看几个问题,假如你对这些问题已经很懂了的话,那大可不用看这篇文章,如果不大懂的话,那么可以看看我的想法。 问题1: public static void main(String[] ar...
作为最基础的引用数据类型,Java 设计者为 String 提供了字符串常量池以提高其性能,那么字符串常量池的具体原理是什么,我们带着以下三个问题,去理解字符串常量池: 字符串常量池的设计意图是什么? 字符串常量池在哪里? 如何操作字符串常量池? 字符串常量池的设计思想 字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价,作为最基础的数据类型,大量频繁的创建字符串,极大程度地影响程...
摘要:那方法区里都存着什么呢先抛结论静态变量常量类信息构造方法接口定义运行时常量池存在方法区中。动态常量池运行时常量池是方法区的一部分,是一块内存区域。文件常量池将在类加载后进入方法区的运行时常量池中存放。 一、方法区与永久代 这两个是非常容易混淆的概念,永久代的对象放在方法区中,就会想当然地认为,方法区就等同于持久代的内存区域。事实上两者是这样的关系: 《Java虚拟机规范》只是规定了有方...
摘要:为了减少在中创建的字符串的数量,字符串类维护了一个字符串常量池。但是当执行了方法后,将指向字符串常量池中的那个字符串常量。由于和都是字符串常量池中的字面量的引用,所以。究其原因,是因为常量池要保存的是已确定的字面量值。 String,是Java中除了基本数据类型以外,最为重要的一个类型了。很多人会认为他比较简单。但是和String有关的面试题有很多,下面我随便找两道面试题,看看你能不能...
摘要:常量池探秘每个文件编译为文件后,都将产生当前类独有的常量池,我们称之为静态常量池。文件中的常量池包含两部分字面值和符号引用。方法的调用成员变量的访问最终都是通过运行时常量池来查找具体地址的。其中,表示将一个常量加载到操作数栈。 java中讲的常量池,通常指的是运行时常量池,它是方法区的一部分,一个jvm实例只有一个运行常量池,各线程间共享该运行常量池。 java内存模型中将内存分为堆和...
阅读 621·2021-11-11 16:55
阅读 2135·2021-11-11 16:55
阅读 1917·2021-11-11 16:55
阅读 2305·2021-10-25 09:46
阅读 1564·2021-09-22 15:20
阅读 2191·2021-09-10 10:51
阅读 1677·2021-08-25 09:38
阅读 2580·2019-08-30 12:48