• JavaSE——字符串常量池(StringTable)


    ced485cbb11e458d81a746890b32cf3f.gif

    作者:敲代码の流川枫

    博客主页:流川枫的博客

    专栏:和我一起学java

    语录:Stay hungry stay foolish

    工欲善其事必先利其器,给大家介绍一款超牛的斩获大厂offer利器——牛客网

    点击免费注册和我一起刷题吧  

    文章目录

    1. 字符串常量池

    2. intern方法

    3. 面试题


    1. 字符串常量池(StringTable)

    为了提升性能和减少内存开销,避免字符串的重复创建,JVM维护了一块特殊的内存空间,就是字符串常量池。字符串常量池由String类私有的维护

    为了节省存储空间以及程序的运行效率,Java中还引入了:

    1. Class文件常量池:每个.Java源文件编译后生成.Class文件中会保存当前类中的字面常量以及符号信息

    2. 运行时常量池:在.Class文件被加载时,.Class文件中的常量池被加载到内存中称为运行时常量池,运行时常量池每个类都有一份

    Java中有两种创建字符串对象的方式:

    1. 直接使用字符串常量进行赋值

    1. public class Test {
    2. public static void main(String[] args) {
    3. String s1 = "hello";
    4. String s2 = "hello";
    5. System.out.println(s1==s2);
    6. }
    7. }
    8. //运行结果:true

    使用String s1 = "hello";创建对象时,JVM先会去字符串池中查找是否存在"hello"这个对象,不存在,则在字符串池中创建"hello"这个对象,然后将池中"hello"这个对象的引用地址返回给字符串常量s1,这样s1会指向池中"hello"这个字符串对象;存在,则不创建任何对象,直接将池中"hello"这个对象的地址返回,赋给字符串常量

     String s2 = "hello";创建对象时,JVM先去字符串常量池找到"hello",并将地址引用给s2,因此如下图看,s1和s2引用指向的value数组是同一个数组

    2. 通过new创建String类对象

    1. public class Test {
    2. public static void main(String[] args) {
    3. String s1 = "hello";
    4. String s2 = "hello";
    5. String s3 = new String("hello");
    6. String s4 = new String("hello");
    7. System.out.println(s3==s4);
    8. //运行结果:false
    9. }
    10. }

    s3和s4创建对象时,首先去字符串常量池中寻找有无"hello",有则不在池中再去创建这个对象了,直接在堆中创建一个"hello"字符串对象,然后将地址返回赋给引用s3或s4,这样就指向了堆中创建的字符串对象;如果没找到,则首先在字符串常量池池中创建一个"hello"字符串对象,然后再在堆中创建一个"hello"字符串对象,然后将地址返回赋给引用,如此就指向了堆中创建的对象

    new关键字创建对象时,new出来的是一个新的对象,也即引用s3和s4指向的是两个不同的对象,因此语句输出:false

    一道题:

    1. //下面代码将输出什么内容:()
    2. public class SystemUtil{
    3. public static boolean isAdmin(String userId){
    4. return userId.toLowerCase()=="admin";
    5. }
    6. public static void main(String[] args){
    7. System.out.println(isAdmin("Admin"));
    8. }
    9. }

    分析:

    首先,==号两边的是引用数据类型,那么比较的是"地址相不相同"

    然后isAdmin()方法中的"admin"是存放在字符串常量池中的,userId.toLowerCase()是new出来的,回的是一个新的对象

    因此输出:false

    2. intern方法

    该方法的作用是手动将创建的String对象添加到常量池中

    1. public class Test {
    2. public static void main(String[] args) {
    3. char[] chars = new char[]{'h','e','l','l','o'};
    4. String s1 = new String(chars);
    5. //s1.intern();
    6. String s2 = "hello";
    7. System.out.println(s1==s2);
    8. }
    9. //运行结果:false
    10. }

    String s1 = new String(chars);时,拷贝一个新的数组赋给s1,即s1指向的是一个新的数组

    String s2 = "hello";时,JVM首先在常量池中寻找"hello",发现没有,就创建一个"hello"存放到常量池中,将地址返回给s2

    因此输出:false

    添加s1.intern();

    1. public class Test {
    2. public static void main(String[] args) {
    3. char[] chars = new char[]{'h','e','l','l','o'};
    4. String s1 = new String(chars);
    5. s1.intern();
    6. String s2 = "hello";
    7. System.out.println(s1==s2);
    8. }
    9. //运行结果:true
    10. }

    s1.intern();将创建的String对象添加到常量池中, String s2 = "hello";时,JVM首先去常量池中寻找,找到"hello",然后将地址返回给s2

    因此输出:true

    3. 面试题

    请解释String类中两种对象实例化的区别(JDK1.8中)

    String str = "hello"

    只会开辟一块堆内存空间,保存在字符串常量池中,然后str共享常量池中的String对象

    String str = new String("hello")

    会开辟两块堆内存空间,字符串"hello"保存在字符串常量池中,然后用常量池中的String对象给新开辟的String对象赋值

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

    现在堆上创建一个String对象,然后利用copyof将重新开辟数组空间,将参数字符串数组中内容拷贝到String对象中

    “ 本期的分享就到这里了, 记得给博主一个三连哈,你的支持是我创作的最大动力!

    ced485cbb11e458d81a746890b32cf3f.gif

  • 相关阅读:
    python数据可视化-matplotlib入门(7)-从网络加载数据及数据可视化的小总结
    二十、Linux网络配置
    Android12.0 系统限制上网系列之iptables用IOemNetd实现app上网黑名单的实现
    【Android-java】通过继承的方式实现对webView的相关设置以达到最大降低成本代码改动量的目的
    操作系统——第一章概论(下)
    小程序源码:纯头像微信小程序源码下载,多分类头像自动采集
    【Transformers】预训练模型使用工具Transformer(1):初识Hugging Face
    全量知识系统 程序详细设计 三次模型:数据模型图算模型和统计模型(Q&A百度文库)
    基于区块链的隐私保护数据共享
    基于SSM的会议室预约系统
  • 原文地址:https://blog.csdn.net/chenchenchencl/article/details/126359224