JavaSE——(面试题)关于String的两种创建方式在内存中的区别

1.方式

  • 通过“字面量赋值”
String str = "Hello"
  • 通过new关键字创建对象
String str = new String("Hello");

2.简单分析

public class Test { 
    public static void main(String[] args) { 
          String str = "Hello";
        } 
 }
  • 上面的例子,Test.java文件编译后得到class文件,里面包含了类的信息,其中有一块叫做常量池的区域,class文件常量池主要存储的就包括字面量,字面量包括类中定义的常量,由于String是不可变的,所以字符串“Hello”就存放在这。
  • 当程序用到Test类时,Test.class被解析到内存中的方法区。.class文件中的常量池信息会被加载到运行时常量池,但String却不是,例子中“hello”会在堆区创建一个对象,同时会在字符串池中存放一个它的引用,此时只是Test类刚刚被加载,主函数中的str并没有被创建,而“Hello”对象已经创建存在于堆中。
  • 所以当主线程开始创建str变量时,虚拟机会去字符串池中找是否有 equals(“Hello”)的String,如果相等就把在字符串池中“Hello”的引用复制给str。如果找不到相等的字符串,就会在堆中新建一个对象,同时把引用驻留在字符串池,再把引用赋给str。
  • 所以当用字面量赋值的方法创建字符串时,无论创建多少次,只要字符串的值相同,它们所指向的都是堆中的同一个对象。
package com.westo.demo1;

public class MyTest1 {
    public static void main(String[] args) {
        String str1="Hello";
        String str2="Hello";
        String str3="He"+"llo";
        String str4="He";
        String str5="llo";
        String str6=str4+str5;
        System.out.println(str1==str2);//true
        System.out.println(str1 == str3);//true
        System.out.println(str1 == str6);//false
    }
}
//为什么str1==str6的结果会是false呢?
//原因:正如前面所说的,str6是由str4和str5拼接起来的,而在编译器无法获取他们的地址,只有在运行之后才能确定,所以他们的地址肯定不同。
  • 当利用new关键字去创建字符串时,前面加载的过程是一样的,只是在运行时无论字符串池中有没有与当前值相等的对象引用,都会在堆中新开辟一块内存,创建一个对象(运行时)
package com.westo.demo1;

public class MyTest1 {
    public static void main(String[] args) {
        String str1="Hello";
        String str2 = new String("Hello");
        String str3 = str2.intern();
        System.out.println(str1==str2);//false
        System.out.println(str1 == str3);//true
    }
}
//str1和str两个“Hello”,一个在编译阶段就在内存中,一个是运行时创建出来的,所以地址不一样
//intern()方法是当常量池中存在当前字符串,就会直接返回当前字符串,所以就是true
总结:
  • 字面量创建字符串会先在字符串池中找,看是否有相等的对象,没有的话就在堆中创建,把地址驻留在字符串池;有的话则直接用池中的引用,避免重复创建对象。
  • new关键字创建时,前面的操作和字面量创建一样,只不过最后在运行时会创建一个新对象,变量所引用的都是这个新对象的地址。
发布了58 篇原创文章 · 获赞 13 · 访问量 1892

猜你喜欢

转载自blog.csdn.net/weixin_44324174/article/details/103757961