资讯专栏INFORMATION COLUMN

String 和常量池

vspiders / 3440人阅读

摘要:方法就是扩充常量池的一个方法当一个实例调用方法时,会查找当前常量池中是否已有相同的字符串常量,如果有就返回其引用,如果没有就在常量池中添加对应的字符串,并返回对应字符串常量的引用。

常量池:在编译被确定,并保存在.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...

    Tamic 评论0 收藏0
  • String:字符串常量

    作为最基础的引用数据类型,Java 设计者为 String 提供了字符串常量池以提高其性能,那么字符串常量池的具体原理是什么,我们带着以下三个问题,去理解字符串常量池: 字符串常量池的设计意图是什么? 字符串常量池在哪里? 如何操作字符串常量池? 字符串常量池的设计思想 字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价,作为最基础的数据类型,大量频繁的创建字符串,极大程度地影响程...

    lidashuang 评论0 收藏0
  • 方法区到底是个什么鬼

    摘要:那方法区里都存着什么呢先抛结论静态变量常量类信息构造方法接口定义运行时常量池存在方法区中。动态常量池运行时常量池是方法区的一部分,是一块内存区域。文件常量池将在类加载后进入方法区的运行时常量池中存放。 一、方法区与永久代 这两个是非常容易混淆的概念,永久代的对象放在方法区中,就会想当然地认为,方法区就等同于持久代的内存区域。事实上两者是这样的关系: 《Java虚拟机规范》只是规定了有方...

    binaryTree 评论0 收藏0
  • 我终于搞清楚了String有关的那点事儿。

    摘要:为了减少在中创建的字符串的数量,字符串类维护了一个字符串常量池。但是当执行了方法后,将指向字符串常量池中的那个字符串常量。由于和都是字符串常量池中的字面量的引用,所以。究其原因,是因为常量池要保存的是已确定的字面量值。 String,是Java中除了基本数据类型以外,最为重要的一个类型了。很多人会认为他比较简单。但是和String有关的面试题有很多,下面我随便找两道面试题,看看你能不能...

    paulli3 评论0 收藏0
  • java 为什么需要常量

    摘要:常量池探秘每个文件编译为文件后,都将产生当前类独有的常量池,我们称之为静态常量池。文件中的常量池包含两部分字面值和符号引用。方法的调用成员变量的访问最终都是通过运行时常量池来查找具体地址的。其中,表示将一个常量加载到操作数栈。 java中讲的常量池,通常指的是运行时常量池,它是方法区的一部分,一个jvm实例只有一个运行常量池,各线程间共享该运行常量池。 java内存模型中将内存分为堆和...

    Yuanf 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<