Java字符串对象池的作用是什么?

Java字符串对象池的作用是什么?

在这里插入图片描述

在这里插入图片描述

在 Java 中,字符串池(String Pool)是字符串常量的存储区域,它位于堆区域中。字符串池的作用是提高字符串的重用性,减少内存消耗。

字符串池的位置:

  1. 在堆中: 字符串池是堆区的一部分。当创建字符串时,Java 首先检查字符串池中是否已经存在相同内容的字符串,如果存在,则直接返回池中的引用,不会重复创建。如果字符串池中没有相同内容的字符串,则将新字符串添加到池中。

  2. String 类中的 intern() 方法: String 类中有一个 intern() 方法,该方法可以手动将字符串对象添加到字符串池中。如果字符串池中已经存在相同内容的字符串,intern() 方法返回池中的引用;否则,将当前字符串对象添加到池中并返回。

与堆中 new 出来的字符串的区别:

  1. 重用性: 字符串池中的字符串具有重用性。如果在字符串池中已经存在相同内容的字符串,不会创建新的对象,而是直接返回现有对象的引用。而使用 new 关键字创建的字符串对象,无论内容是否相同,都会在堆中创建一个新的对象。

  2. 比较: 字符串池中的字符串可以使用 == 进行比较,因为它们是相同对象的引用。而在堆中通过 new 创建的字符串,应该使用 equals() 方法进行内容比较,因为它们可能是不同的对象。

示例代码:

String str1 = "Hello";         // 字符串池中创建
String str2 = "Hello";         // 直接使用字符串池中的引用
String str3 = new String("Hello"); // 在堆中创建新的字符串对象

System.out.println(str1 == str2);  // true,因为它们引用相同的对象
System.out.println(str1 == str3);  // false,因为它们引用不同的对象
System.out.println(str1.equals(str3)); // true,因为它们内容相同

总体来说,使用字符串池可以减少内存占用,提高字符串的比较效率。在大部分情况下,推荐使用字符串池来创建字符串对象。

在 Java 中,可以使用 System.identityHashCode() 方法来获取对象的哈希码,从而间接获取对象的地址。以下是一个例子,演示了使用 new 关键字创建字符串和使用字符串池创建字符串的地址输出:

public static void main(String[] args) {
        String str1 = "Hello";         // 字符串池中创建
        String str2 = "Hello";         // 直接使用字符串池中的引用
        String str3 = new String("Hello"); // 在堆中创建新的字符串对象
        String str4 = "Hello";         // 直接使用字符串池中的引用

        System.out.println(str1 == str2);  // true,因为它们引用相同的对象
        System.out.println(str1 == str3);  // false,因为它们引用不同的对象
        System.out.println(str1.equals(str3)); // true,因为它们内容相同
        System.out.println("Address of str1 (str1): " + System.identityHashCode(str1));// Address of str1 (str1): 2065951873
        System.out.println("Address of str2 (str2): " + System.identityHashCode(str2));// Address of str2 (str2): 2065951873
        System.out.println("Address of str3 (str3): " + System.identityHashCode(str3));// Address of str3 (str3): 1922154895
        System.out.println("Address of str4 (str4): " + System.identityHashCode(str4));// Address of str4 (str4): 2065951873
    }

通过 System.identityHashCode() 输出它们的地址信息。请注意,具体的地址值可能会因为不同的 JVM 实现而有所不同。

true
false
true
Address of str1 (str1): 2065951873
Address of str2 (str2): 2065951873
Address of str3 (str3): 1922154895
Address of str4 (str4): 2065951873

在这里插入图片描述

Java中的字符串

Java中没有原生的字符串类型,但是提供了StringStringBufferStringBuilder来表示字符串,在它们的代码实现中都是通过char[]来存储字符串中的字符的。下图是它们的继承关系:
在这里插入图片描述

StringStringBufferStringBuilder 是 Java 中用于处理字符串的三个主要类,它们在设计和使用上有一些关键的区别。

String 类:

  1. 不可变性: String 对象是不可变的,一旦创建,其内容不能被修改。任何对 String 类的操作都会创建一个新的字符串对象。

  2. 线程安全性: 由于不可变性,String 对象是线程安全的,可以在多个线程中共享。

  3. 使用场景: 适用于字符串内容不经常变化的场景,例如字符串常量、配置信息等。

public class Main{
    public static void main(String[] args) {
        String str = "Hello";
        System.out.println("Address of str (str): " + System.identityHashCode(str));//
        str = str + " World";  // 创建了一个新的字符串对象
        System.out.println("Address of str (str): " + System.identityHashCode(str));//
        System.out.println("Address of str (str): " + System.identityHashCode("Hello"));//
        System.out.println("Address of str (str): " + System.identityHashCode("World"));//

    }
}

结果

Address of str (str): 2065951873
Address of str (str): 883049899
Address of str (str): 2065951873
Address of str (str): 2093176254

StringBuffer 类:

  1. 可变性: StringBuffer 是可变的,可以通过其方法对字符串进行修改,而不创建新的对象。

  2. 线程安全性: StringBuffer 是线程安全的,所有的方法都是同步的,适合在多线程环境下使用。

  3. 使用场景: 适用于频繁修改字符串的场景,例如拼接大量字符串。

public class Main{
    public static void main(String[] args) {
        StringBuffer buffer = new StringBuffer("Hello");
        System.out.println("Address of str (buffer): " + System.identityHashCode(buffer));//
        buffer.append(" World");  // 在原有对象上进行修改
        System.out.println("Address of str (buffer): " + System.identityHashCode(buffer));//
        System.out.println("Address of str (Hello): " + System.identityHashCode("Hello"));//
        System.out.println("Address of str ( World): " + System.identityHashCode(" World"));//

    }
}

结果

Address of str (buffer): 2065951873
Address of str (buffer): 2065951873
Address of str (Hello): 1922154895
Address of str ( World): 883049899

StringBuilder 类:

  1. 可变性: StringBuilder 也是可变的,类似于 StringBuffer,但不同的是它的方法不是同步的,因此在单线程环境下使用更高效。

  2. 线程安全性: StringBuilder 不是线程安全的,不适合在多线程环境下使用。

  3. 使用场景: 适用于单线程环境下频繁修改字符串的场景,性能比 StringBuffer 更好。

public class EventOverlapChecker {
    public static void main(String[] args) {
        StringBuilder builder = new StringBuilder("Hello");
        System.out.println("Address of str (builder): " + System.identityHashCode(builder));//
        builder.append(" World");  // 在原有对象上进行修改
        System.out.println("Address of str (builder): " + System.identityHashCode(builder));//
        System.out.println("Address of str (Hello): " + System.identityHashCode("Hello"));//
        System.out.println("Address of str ( World): " + System.identityHashCode(" World"));//
    }
}

结果

Address of str (builder): 2065951873
Address of str (builder): 2065951873
Address of str (Hello): 1922154895
Address of str ( World): 883049899

总结比较:

  • 如果字符串内容基本不变,且需要频繁操作,使用 StringBufferStringBuilder
  • 如果字符串内容基本不变,不需要频繁操作,使用 String
  • 如果字符串内容可能会改变,且在多线程环境下使用,使用 StringBuffer
  • 如果字符串内容可能会改变,且在单线程环境下使用,使用 StringBuilder
    在这里插入图片描述

字符串常量池

由于字符串的不可变性以及字符串使用的频繁性,JVM在堆中通过哈希表实现了一个字符串常量池,用于避免字符串的重复创建。在使用字符串字面量实例化字符串对象时,如果字符串常量池中没有该字符串,就会将该字符串实例化并将该字符串的引用加入字符串常量池;如果字符串常量池中有该字符串引用,那么就会直接返回该引用。

public static void main(String[] args) {
    String str1 = "helloWorld";
    String str2 = "helloWorld";
    System.out.println(str1 == str2);//true
}

在这里插入图片描述

String str1=new String("helloWorld");
String str2=new String(new char[]{'h','e','l','l','o','W','o','r','l','d'});

在这里插入图片描述
再看str2,就只有一个new出来的对象:

在这里插入图片描述

String str=new String("helloWorld");
System.out.println(str.intern()==str);//false

在这里插入图片描述

String str=new String("hello")+new String("World");
System.out.println(str.intern()==str);//true

在这里插入图片描述

在 Java 中,字符串池中实际上保存的是字符串对象的引用,而不是在堆中存储字符串对象的地址。每个字符串池中的引用指向在堆中实际存储的字符串对象。

字符串是不可变的,当我们创建一个字符串时,如果字符串池中已经存在相同内容的字符串,则直接返回池中的引用。如果字符串池中没有相同内容的字符串,会创建一个新的字符串对象,并将其引用加入到字符串池中。

这种机制有助于提高字符串的重用性,减少内存占用。因为相同的字符串在池中只保存一份,多个字符串变量可以共享相同的引用,而不需要重复创建相同的字符串对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/297751.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Qt6入门教程 3:创建Hello World项目

一.新建一个项目 程序员的职业生涯都是从一声问候开始的,我们的第一个Qt项目也是HelloWorld 首先要说明的是,IDE不一定要用Qt Creator,用Visual Studio、VSCode、CLion也可以搭建Qt开发环境,它们都相应的插件来支持Qt开发。当然这…

气动凝结水回收机组 浮球机械泵回收机组工作原理动画讲解介绍

​ 1:气动凝结水回收浮球机械泵介绍 气动凝结水回收是一种利用气动力转换产生负压的装置,可以将废气中的水分分离出来并回收利用。这种装置主要包含两个关键部件:气水分离器和气动运动控制阀。 气水分离器负责将进入回收装置的废气中的水分…

transforms图像增强(二)

一、图像变换 1、transforms.Pad transforms.Pad是一个用于对图像边缘进行填充的数据转换操作。 参数: padding:设置填充大小。可以是单个整数,表示在上下左右四个方向上均填充相同数量的像素;也可以是一个包含两个整数的元组…

粉丝投稿:从写下第1个脚本到年薪20W,我的自动化测试心路历程

我希望我的故事能够激励现在的软件测试人,尤其是还坚持在做“点点点”的测试人。 你可能会有疑问:“我也能做到这一点的可能性有多大?”因此,我会尽量把自己做决定和思考的过程讲得更具体一些,并尽量体现更多细节。 每…

印象笔记02: 笔记本管理系统和空间使用

印象笔记02: 笔记本管理系统和空间使用 印象笔记新建笔记是一件非常容易的事情。笔记多了,就是归纳到笔记本里。 印象笔记一共有三层的笔记结构:最高层级是笔记本组,其次是笔记本,最后是一个个的笔记。合理的分类能够…

SpringCloud系列篇:核心组件之注册中心组件

🥳🥳Welcome Huihuis Code World ! !🥳🥳 接下来看看由辉辉所写的关于SpringCloud的相关操作吧 目录 🥳🥳Welcome Huihuis Code World ! !🥳🥳 一.注册中心组件是什么 二.注册中心…

一键转换,创新无限:将HTML轻松转化为PDF!

在数字时代,HTML与PDF已成为信息传递的两大主流格式。然而,在这两者之间转换常常让人感到困扰。现在,有了我们的创新工具,您只需轻点一下,即可一键将HTML转化为PDF! 首先,我们要进入首助编辑高…

(Python + Selenium4)Web自动化测试自学Day2之动手尝试

目录 文章声明⭐⭐⭐让我们开始今天的学习吧!小试牛刀关于select标签关于弹窗只有一个点击按钮的弹窗需要确认的弹窗用户可以输入的弹窗 文章声明⭐⭐⭐ 该文章为我(有编程语言基础,非编程小白)的 Python Selenium4 Web自动化测试…

HttpRunner自动化测试工具之获取响应数据extract提取值到变量

获取响应数据 extract: 提取 注:extract 应与request保持同一层级 1、响应行,响应头;通过 extract 提取响应的数据并存储到变量中,如下图: 注:变量名的前面要有 - # 获取响应数据: 响应行(…

【年终总结系列 2023】成长与收获:回顾过去、展望未来,加油2024!

转眼间加入CSDN已经六年多了,初加入CSDN时,我兴致勃勃地投入到写作中,分享了一些CTF的解题思路和方法,取得了不错的反响。但随着工作忙碌和生活压力的增加,我在CTF方面的写作频率逐渐减少,也很长时间没有更…

Linux离线安装MySQL(rpm)

目录 下载安装包安装MySQL检测安装结果服务启停MySQL用户设置 下载安装包 下载地址:https://downloads.mysql.com/archives/community/ 下载全量包如:(mysql-8.1.0-1.el7.x86_64.rpm-bundle.tar) 解压:tar -xzvf mysql-8.1.0-1.el7.x86_64.…

国家高等教育智慧教育平台

文章目录 1. 网站地址2. 网站简介3. 网站集合的资源与依托平台彩蛋环节a. 考试酷b. 公益学术平台 足不出户,就能免费学习2.7万门大学课程。包含国家精品课程,部分课程由国家级名师 / 院士 授课。 1. 网站地址 国家高等教育智慧教育平台网址:…

架构的本质是什么?

最近总是有小伙伴问我,如何成长为一名优秀的架构师,我也不知道该如何去回答,但是我想聊一下架构的本质。 架构不是互联网行业独有的 架构及对应的架构师职位并不是互联网行业独有的,只要存在组织的地方就存在架构。 比如一个木…

【C++】vector

文章目录 1. vector 的介绍2. vector 的使用2.1 vector 的定义2.2 vector iterator 的使用2.3 vector 的空间增长问题2.3 vector 增删查改 1. vector 的介绍 vector的文档介绍 vector是表示可变大小数组的序列容器。就像数组一样,vector也采用连续的存储空间来存储…

程序员必知!责任链模式的实战应用与案例分析

责任链模式让多个对象依次处理请求,降低发送者和接收者的耦合度,以在线购物为例,用户提交订单需经多步验证,通过责任链模式,验证器按顺序处理请求,先用户身份,再支付方式,最后配送地…

【LMM 011】MiniGPT-5:通过 Generative Vokens 进行交错视觉语言生成的多模态大模型

论文标题:MiniGPT-5: Interleaved Vision-and-Language Generation via Generative Vokens 论文作者:Kaizhi Zheng* , Xuehai He* , Xin Eric Wang 作者单位:University of California, Santa Cruz 论文原文:https://arxiv.org/ab…

java的面向对象编程(oop)概述及案例

前言: 学到了面向对象编程,整理下相关知识点。打牢基础,daydayup! 面向对象基础概述 1,什么是面向对象,面向对象的思考逻辑是什么? 面向对象就是把任何事物都看成一个又一个对象。思考逻辑为万物皆对象&am…

计算机毕业设计 基于javaweb的宠物认养系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ 🍅文末获取源码联系🍅 👇🏻 精…

STHS34PF80人体存在传感器(1)----获取人体存在状态

STHS34PF80人体存在传感器.1--获取人体存在状态 概述视频教学样品申请完整代码下载主要特点硬件准备接口最小系统图生成STM32CUBEMX串口配置IIC配置CS设置串口重定向参考案例获取ID温度测量滤波方式智能识别算法使用块数据更新(BDU)功能设置ODR速率获取状…

多类指针式仪表自动读数系统的LabVIEW开发应用案例

多类指针式仪表自动读数系统的LabVIEW开发应用案例 工业环境中,多类指针式仪表的自动读数一直是一个具有挑战性的问题。本案例旨在展示如何使用LabVIEW开发一个高度智能化的多类指针式仪表自动读数系统,以应对复杂的工业环境。通过结合图像处理技术和深…