zoukankan      html  css  js  c++  java
  • Java进阶——Java中的字符串常量池

     

    字符串常量池

    JVM为了减少字符串对象的重复创建,其内部维护了一个特殊的内存,这段内存被成为字符串常量池(方法区中)。实际上还有整型常量池、浮点型常量池等等。字符串常量池存放的是对象的引用,而不是对象。Java中字符串对象创建有两种形式:字面量形式和创建对象形式

    1、字面量形式

    字面量的体现形式String str = "Hello",简单理解为去字符串常量池中拿对象的引用

    当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用

    2、创建对象形式

    创建对象的体现形式String str = new String("Hello");,简单理解为直接在堆内存空间中创建新的对象

    当代码中出现了new来构造字符串对象的时候,不管字符串常量池中有没有相同内容的对象的引用,首先它都会去创建这个字符串对象,这里字符串对象指的是String对象,String对象存放在堆当中。然后它会去字符串常量池寻找Hello这个字符串,其处理的结果同字面量形式。最终str引用指向String对象的引用

    字符串对象创建

    1、String str = new String(“abc”) 创建多少个对象?2个

    1. 在常量池中查找是否有”abc”对象,有则返回对应的引用实例,没有则创建对应的实例对象(1个)
    2. 在堆中 new 一个 String(“abc”) 对象(1个)
    3. 将对象地址赋值给str,创建一个引用

    2、String str = new String(“A”+”B”)创建多少个对象?4个

    1. 在常量池中查找,字符串”A”,”B”,”AB”(3个)
    2. 在堆中 new 一个 String(“AB”) 对象(1个)
    3. 将对象地址赋值给str,创建一个引用

    问题抛出

    问:求解下面的输出语句的结果并解释原因

    String s1 = "Hello";
    String s2 = "Hello";
    String s3 = "Hel" + "lo";
    String s4 = "Hel" + new String("lo");
    String s5 = new String("Hello");
    String s6 = s5.intern();
    String s7 = "H";
    String s8 = "ello";
    String s9 = s7 + s8;
    
    // == :比较两个对象是否为同一对象
    System.out.println(s1 == s2);  // true
    System.out.println(s1 == s3);  // true
    System.out.println(s1 == s4);  // false
    System.out.println(s1 == s9);  // false
    System.out.println(s4 == s5);  // false
    System.out.println(s1 == s6);  // true

    问题分析

    1、s1==s2

    s1和s2在赋值时,均使用的字符串字面量。在编译期间,这种字面量会直接放入常量池中,从而实现复用。在载入运行时常量池后,s1和s2指向的是同一个内存地址

    2、s1==s3

    s3是动态拼接出来的字符串,但是所有参与拼接的部分都是已知的字面量。在编译期间,这种拼接会被优化,编译器直接帮你拼好,因此s3会被优化成String s3 = "Hello"

    3、s1==s4

    s4是动态拼接出来的字符串,但new String("lo")这部分不是已知字面量,是一个不可预料的部分。在编译期间,编译器不会优化,必须等到运行时才可以确定结果

    4、s1==s9

    s7和s8在赋值的时候使用的字符串字面量,但是拼接成s9的时候,s7和s8作为两个变量,都是不可预料的。编译器毕竟是编译器,不可能当解释器用,所以不做优化。等到运行时,s7和s8拼接成的新字符串,在堆中地址不确定,不可能与方法区常量池中的s1地址相同

    5、s4==s5

    s4和s5都创建出了字符串对象,两者都存在于堆中,但地址不相同

    6、s1==s6

    对于使用new创建的字符串对象,如果想将这个对象的引用加入到字符串常量池,可以使用intern方法。调用intern后,首先检查字符串常量池中是否有该对象的引用,如果存在,则将这个引用返回给变量,否则将引用加入并返回给变量。很显然,s1和s6都已经是字符串常量池中的一员,且值是相等的,所以引用的地址也相等

  • 相关阅读:
    Java: 数据类型
    数据结构是什么
    数据结构:进制转换
    数据结构:堆与栈
    class的写法
    Java:异常体系
    数据结构: 先进后出——堆栈
    tomcat:web容器
    Windows: Dos命令
    面向函数范式编程
  • 原文地址:https://www.cnblogs.com/shoshana-kong/p/11249307.html
Copyright © 2011-2022 走看看