Java中String类的常见问题

news2024/10/6 4:09:37

目录

Q1:为什么String类要定义成不可变类型?

方便String对象缓存HashCode值

字符串常量池的需要

衍生问题:String str = new String("hello world") 创建了几个对象?

为了保障程序的安全性

Q2:String的不可变特性体现在哪?

Q3:JDK9之后的String类为什么要变为byte数组?

Q4:为什么不推荐String类用于字符串拼接?

Q5:String.intern()方法的作用?不同JDK版本有何区别?

String.intern()是什么?

intern方法在不同JDK版本中的区别?


Q1:为什么String类要定义成不可变类型?

方便String对象缓存HashCode值

在日常工作中,String对象常用作HashMap等容器中作为键值对的(key)键存在,它会用于计算哈希桶的索引位置。故String对象设计为不可变可以保障每次计算的哈希码为固定值,因此可以放心地作为HashMap中的key出现。且String类中定义了一个成员变量来存储哈希值,这体现了一种性能优化手段,意味着不必每次都去计算哈希码。

String类默认重写了equals 和 HashCode方法,也就说明可以进行等值判断。

字符串常量池的需要

字符串常量池是Java堆内存中一个特殊的存储区域。当创建一个String对象时,如果该字符串已经存在于常量池中,则不会创建一个新对象,而是将变量指向常量池中已经存在的那个字符串对象。

String str1 = "hello world";
String str2 = "hello world";

上面示例代码虽然定义了两个String对象,但实际在堆内存中只存在一份 "hello world" 对象。

内存布局如下所示:

衍生问题:String str = new String("hello world") 创建了几个对象?

这个问题有两个回答:2或1

为2的情况:

字符串常量池中不存在"hello world",这时在堆内存中的新生代伊甸园区(大对象可能会分配在老年代)需要创建一个String类型的对象,且还需要在字符串常量池中放入一个值为 "hello world" 的对象。

为1的情况:

字符串常量池中存在值为"hello world"的String对象,这时在堆内存中的伊甸园区需要创建一个String类型的对象,其它不需要再创建额外对象。

为了保障程序的安全性

String类被许多其它的Java类库用来当做参数,例如网络连接地址URL,反射机制所需要的String参数等等。假若String是可变类型,在网络连接被攻击时将会引起各种安全隐患。

Q2:String的不可变特性体现在哪?

以JDK8作为demo,看看类的设计有哪些体现了String不可变性

大家都知道,在类上加上final关键字会使该类会拥有不可被其它类继承的特性,变量上使用该关键字会使其引用地址不可被更改【内部数值可以更改】。很多人误以为这两点是String类不可变的最大功臣,其实不然,String类不可变的根本原因是因为它是使用一个内部私有【外部类不可见】的 char数组来实现,且类内部没有对外提供修改该数组的方法。

Q3:JDK9之后的String类为什么要变为byte数组?

承接上文,JDK9之前String类中使用的是char数组,为什么在后续版本中要更换为byte数组呢?

先给出结论:优化Java虚拟机(JVM)中String对象占用的内存大小

具体理由如下:

char类型的数据在JVM中占用了两个字节的空间,使用的是UTF-16编码。这就导致了原本String中的字符原本仅需一个字节表示的对象会占用两个字节,且实际工作经验表明使用频率最高的还是单字节的字符。所以将原本的char数组更换为byte数组,并提供了一个编码标志位属性coder,用来表示不同编码格式。

且后续更新中还新增了一个优化字符串的属性COMPACT_STRINGS

这个字段翻译过来的意思很好理解,就是压缩字符串,静态代码块中默认赋值为true。

它在String对象的构造器中发挥着巨大作用

这段代码非常好理解,COMPACT_STRINGS = true时尝试对字符串进行压缩,将coder = LATIN1

对于 String str = "hello" 来说,JDK9之前可能至少需要10个字节来存储,但优化后仅需5个字节。

Q4:为什么不推荐String类用于字符串拼接?

先来看看String类中对于字符串拼接是怎样实现的。

对于如下这段代码,使用javap -c StringTest.class 查看字节码文件

红框中也就是字符串拼接的核心操作【之前JDK版本中是利用StringBuilder对象进行拼接】

参考其它博主的字节码

上述的makeConcatWithConstants 其实是通过动态调用的方式执行java.lang.invoke.StringConcatFactory类中的makeConcatWithConstants方法进行字符串连接。

尽管JDK团队已经对其进行了优化,但效率与StringBuilder及StringBuffer比还是惨不忍睹。

下面做一个效率测试,三者对同一个字符串对象进行拼接,循环1万次,统计耗时。

public class StringTest2 {

    private static final long TEN_THOUSAND = 10000;

    public static void main(String[] args) {
        String str = "string";
        StringBuilder stringBuilder = new StringBuilder("stringBuilder");
        StringBuffer stringBuffer = new StringBuffer("stringBuffer");
        System.out.println("string...");
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < TEN_THOUSAND; i++) {
            str += i;
        }
        System.out.println("string耗时:" + (System.currentTimeMillis() - startTime) + " ms");

        System.out.println("stringBuilder...");
        long startTime2 = System.currentTimeMillis();
        for (int i = 0; i < TEN_THOUSAND; i++) {
            stringBuilder.append(i);
        }
        System.out.println("stringBuilder:" + (System.currentTimeMillis() - startTime2) + " ms");

        System.out.println("stringBuffer...");
        long startTime3 = System.currentTimeMillis();
        for (int i = 0; i < TEN_THOUSAND; i++) {
            stringBuffer.append(i);
        }
        System.out.println("stringBuffer:" + (System.currentTimeMillis() - startTime3) + " ms");
    }
}

程序运行结果如下:

结果很明显了...,对于后两者来说,StringBuffer适合用于多线程下的字符串操作,因为其内部使用synchronized关键字保证线程安全,而StringBuilder不具有该特性。

Q5:String.intern()方法的作用?不同JDK版本有何区别?

String.intern()是什么?

String.intern()是一个Native方法,底层调用C++的 StringTable::intern方法实现。当通过语句str.intern()调用方法后,JVM 就会在当前类的常量池中查找是否存在与str等值的String,若存在,则直接返回常量池中相应String的引用;若不存在,则会在常量池中创建一个等值的String,然后返回这个String在常量池中的引用。

intern方法在不同JDK版本中的区别?

在JDK6中,JVM中的字符串常量池还在永久代。调用intern方法时,若常量池不存在等值的字符串,JVM就会在字符串常量池创建一个等值的字符串,然后返回该字符串的引用。

在JDK6之后,JVM中的字符串常量池被移到了堆空间中。调用intern方法时,与JDK6不同的是,若常量池不存在等值的字符串,这时复制堆空间中等值字符串的引用到常量池中并返回。

参考链接:

https://blog.csdn.net/qq_45800640/article/details/120284367

Java编程笔记11:字符串_魔芋红茶的博客-CSDN博客

谈谈String.intern方法_求你了,别走。的博客-CSDN博客_string.intern

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2022年深度学习在时间序列预测和分类中的研究进展综述

时间序列预测的transformers的衰落和时间序列嵌入方法的兴起&#xff0c;还有异常检测、分类也取得了进步 2022年整个领域在几个不同的方面取得了进展&#xff0c;本文将尝试介绍一些在过去一年左右的时间里出现的更有前景和关键的论文&#xff0c;以及Flow Forecast [FF]预测…

解决Windows莫名其妙地从休眠状态唤醒的问题

因为经常写代码开很多个工作区&#xff0c;电脑经常就是合盖休眠&#xff0c;这样打开就能用&#xff0c;但是总是在我不经意的时候发现电脑风扇在狂转&#xff0c;不知道是哪个应用又在qj我的电源管理计划&#xff0c;今天午休发现电脑风扇狂转&#xff0c;打开发现是windows系…

c语言操作符(下)

前言 &#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏: &#x1f354;&#x1f35f;&#x1f32f; c语言初阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f349;本篇简介:>: 讲解c语言中有关操作符的知识. 金句分享: ✨✨✨行程…

我用python写了个小病毒,老板再也不敢扣我工资啦

名字&#xff1a;阿玥的小东东 学习&#xff1a;python正在学习c 主页&#xff1a;阿玥的小东东 今天做个什么呢&#xff0c;我的好朋友提议做一个关机的代码吧&#xff0c;我这一想&#xff0c;对吼&#xff0c;我以前还做过一个关机代码呢&#xff0c;于是乎&#xff0c;今天…

时序收敛技巧之寄存器复制

1、何时需要复制寄存器&#xff1f; 在设计中的关键路径发现某个寄存器具有高扇出和高延迟时&#xff0c;使用寄存器复制是个不错的实现时序收敛的方法。下图是一个典型的例子&#xff1a; 可以看出&#xff0c;第一个寄存器的 IC(InterConnect) 延迟为 1.476ns&#xff0c;该寄…

seo站内优化的方法有哪些(站内优化和站外优化)

站内部优化什么意思 网站优化公司的内部优化意味着什么&#xff1f;网站内部优化&#xff0c;就是网站关键词优化、内容优化、内链优化等等&#xff0c;网站要有一定的排名和流量&#xff0c;要做到内部优化&#xff0c;要做到最快&#xff0c;最快的优化排名&#xff1f;接下…

「认知」打工人的自我修养

都说认知以外的钱难搞&#xff0c;那认知内的呢&#xff1f; 01互联网内卷年代&#xff0c;作为不着调的普通选手&#xff1b; 在诸多花里胡哨的黑话中&#xff0c;个人最待见的就是"认知"这个词&#xff1b; 认知&#xff0c;有强烈的抽象感&#xff1b; 想要深刻…

Mr. Cappuccino的第37杯咖啡——Kubernetes资源管理

Kubernetes资源管理kubectl常用的命令陈述式管理方法1. 创建一个namespace2. 查询所有namespace3. 在namespace下运行一个pod4. 查询指定namespace下的pod5. 查看指定pod的详细信息6. 删除pod7. 删除namespace声明式管理方法命令式对象配置1. 创建yaml文件2. 基于yaml文件创建资…

【JavaEE】多线程(初阶)

目录 Thread 线程的创建 线程的常见属性 中断线程 等待线程 休眠线程 线程的状态 多线程相比于单线程的优势 Thread 在Java中操作多线程&#xff0c;最常用的类就是Thread。 Thread 类是 JVM 用来管理线程的一个类&#xff0c;换句话说&#xff0c;每个线程都有一个唯一…

一网打尽带环链表问题(手把着手带你理解,木有基础也能看懂!)

目录 0.前言 1.认识带环链表 2.带环链表OJ问题简述 3.判断是否为带环链表 4. 寻找入环节点&#xff08;法一&#xff1a;数学推理的魅力&#xff09; 5. 寻找入环节点&#xff08;暴力拆解带环链表的魄力&#xff09; 6.番外&#xff1a;判断是否为带环链表(fast和slow的…

树上的DP

ACACAC来的如此之快&#xff0c;让我以为还要再调试几个点(h)&#xff0c;本文涉及思路参考&#xff1a;参考文章 嗯,这个题和思路让我对跨父节点的树上链有了一个认识&#xff0c;我们来看一下&#xff1a; 如果说&#xff0c;我们要对这样的一条链进行dpdpdp操作&#xff0c…

[GXYCTF2019]BabysqliV3.0

发现我们随便上传一个以后返回的是 alert(Wrong pass); 密码错误 如果上传一个账号永真的话返回 Not this user! 没有这个用户&#xff0c;所以感觉可以使用盲注&#xff0c;对账号进行盲注 可是题目 ascii(substr((select database()),1,1))>1 也不对 最后才知道是…

电脑组装配件知识

目录 1.电脑硬件基础知识 1.1CPU 1.2内存 ​编辑 1.3硬盘 1.4主板 1.5显卡 ​编辑 1.6显示器 1.7电源 1.8机箱 2.电脑硬件搭配及选购 2.1硬件搭配原则 2.2怎样查询软件或游戏配置 2.3配件购买注意事项 2.4搭配一台普通办公电脑 3.电脑组装 1.电脑硬件基础知识 …

软件测试/测试开发 | 一文学会 Appium 环境配置

Appium 是一个开源的、跨平台的测试框架&#xff0c;可以用来测试 Native App、混合应用、移动 Web 应用&#xff08;H5 应用&#xff09;等&#xff0c;也是当下互联网企业实现移动自动化测试的重要工具。Appium 坚持的测试理念&#xff1a; •无需用户对 App 进行任何修改或…

OAuth2.0 开放平台认证授权开发套件 Authmore-Framework 1.0 发布

简介 | Intro 基于 OAuth2.0 协议的开放平台认证授权开发套件, 包含授权服务和开放平台 Docker 镜像&#xff0c;基于 Spring Boot Starter 的资源服务工具包和客户端&#xff08;第三方应用&#xff09;工具包 优点 | Advantages 简洁&#xff1a;专注核心功能 —— 社会化…

剑指offer----C语言版----第十六天----面试题22:链表中的倒数第k个节点

目录 1. 链表中倒数第 k 个节点 1.1 题目描述 1.2 思路一 1.3 思路二&#xff1a; 1.4 总结----代码的鲁棒性 1. 链表中倒数第 k 个节点 原题链接&#xff1a; 剑指 Offer 22. 链表中倒数第k个节点 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/l…

竹制品行业市场运行态势及未来前景分析

2023-2029年中国竹制品行业市场运行态势及未来前景分析报告报告编号&#xff1a;1691644免费目录下载&#xff1a;http://www.cninfo360.com/yjbg/qthy/qt/20230110/1691644.html本报告著作权归博研咨询所有&#xff0c;未经书面许可&#xff0c;任何组织和个人不得以任何形式复…

基于Power BI的终端消费会员客户价值RFM分析

一、原理&#xff1a;RFM分析 &#xff08;一&#xff09;概念 RFM模型衡量当前客户价值和客户潜在价值的重要工具和手段。通过一个客户的近期购买行为、购买的总体频率以及花了多少钱三个维度来描述该客户价值状况的客户分类模型。 &#xff08;二&#xff09;分析维度 R&a…

使用标量衍射理论和菲涅耳和弗劳恩霍夫衍射的衍射对波动光学进行建模(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 本文使用Matlab对波动光学进行建模。包括使用标量衍射理论和菲涅耳和弗劳恩霍夫衍射的衍射。 &#x1f4da;2 运行结果 &#…

北大硕士LeetCode算法专题课-栈、队列相关问题

算法面试相关专题&#xff1a; 北大硕士LeetCode算法专题课--链表相关问题_ 北大硕士LeetCode算法专题课-查找相关问题_ 北大硕士LeetCode算法专题课-字符串相关问题_ 北大硕士LeetCode算法专题课-数组相关问题_ _ 北大硕士LeetCode算法专题课-基础算法之排序_ 北…