【面试突击】Java中String类为什么要设计成final?

Java面试30天突击攻略:从八股文到AI大模型应用开发 Java并发编程和JVM调优是后端开发的核心技术领域,理解其原理对于构建高性能、高可用的系统至关重要。Java并发通过synchronized、volatile、CAS等机制保障线程安全,而JVM的垃圾回收算法与内存区域管理则直接影响应用性能。这些技术价值在于能有效解决高并发场景下的数据一致性问题,并优化系统资源利用率,避免内存泄漏和频繁GC。在实际应用中,它们支撑着电商秒杀、金融交易等关键业务系统。本文聚焦于Java面试准备,提供了一套为期30天的结构化学习方案,系统覆盖Java基础、并发、JVM、MyS 阅读详情

talk is cheap, show me the code.

什么是不可变?

String a = "abcd";
a = "abcdef";

大多数人看了上面这两句代码,都认为a由abcd变成了abcdef,而且a是String类型的,这句String不可变不攻自破啊?那么真的是这样吗?
这个理解是错误的。大多数人对String不可变这句话的理解都容易陷入上面这种思想。
而这两句代码的真正含义是:
首先将String类型的变量a赋值为abcd,再将变量a赋值为abcdef。
进行第二次赋值时不是在原内存地址上进行修改数据,而是在堆中建了一个新的String对象,并将栈中的引用指向了这个新对象,新地址。
所以abcd这个字符串对象从创建出来后,始终都没有被改变。

String为什么不可变?

翻开JDK源码,java.lang.String类起手前三行,是这样写的:

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
    /** String本质是个char数组. 而且用final关键字修饰.*/
    private final char value[];
	...
	...
}

首先String类是用final关键字修饰,这说明String不可继承。
再看下面,String类的主力成员字段value是个char[ ]数组,而且是用final修饰的。final修饰的字段创建以后就不可改变。

有的人以为故事就这样完了,其实没有。
因为虽然value是不可变,也只是value这个引用地址不可变。
挡不住Array数组是可变的事实。

Array的数据结构看下图

在这里插入图片描述
也就是说value只是在栈中存了这个数组的引用地址,数组的本体结构在堆。
同理,String类里的value用final修饰,只是value在栈中存的这个数组的引用地址不可变,但是可以改变堆中的这个数组的内容。

看下面这个例子

final int[] value={1,2,3}
int[] another={4,5,6};
value = another;    //编译器报错,final不可变

value用final修饰,编译器不允许我把value指向堆区另一个地址。
但如果我直接对数组元素动手,分分钟搞定。如:

final int[] value={1,2,3};
value[2]=100;  //这时候数组里已经是{1,2,100}

或者更粗暴的反射直接改,也是可以的。如:

final int[] array={1,2,3};
Array.set(array,2,100); //数组也被改成{1,2,100}

所以String是不可变,关键是因为SUN公司的工程师,在后面所有String的方法里很小心的没有去动Array里的元素,没有暴露内部成员字段。

private final char value[]这一句里,使用private修饰value,保证外部不可见;使用final修饰value,保证内部不改变value的引用。
而且设计师还很小心地把整个String设成final禁止继承,避免被其他人继承后破坏。
所以String是不可变的关键都在底层的实现,而不单单是一个final的功劳。
考验的是工程师构造数据类型,封装数据的功力。

不可变有什么好处?

最简单的原因,就是为了安全。

示例1

String a, b, c;
a = "test";
b = a;
c = b;

a += "A";
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println();


b += "B";
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println();

c += "C";
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println();

控制台输出

testA
test
test

testA
testB
test

testA
testB
testC

从示例一的输出可以看出String为不可变的时候,b、c是通过引用传递的方式进行赋值,
虽然一开始三个变量都指向了同一个地址,但是改变了a的值,并没有影响后面b、c的使用。

如果String是可变的,就可能如下例,我们使用StringBuffer来模拟String是可变的:

StringBuffera, b, c;
a = new StringBuffer("test");
b = a;
c = b;

a.append("A");
System.out.println(a.toString());
System.out.println(b.toString());
System.out.println(c.toString());
System.out.println();

b.append("B");
System.out.println(a.toString());
System.out.println(b.toString());
System.out.println(c.toString());
System.out.println();

c.append("C");
System.out.println(a.toString());
System.out.println(b.toString());
System.out.println(c.toString());
System.out.println();

控制台输出

testA
testA
testA
testAB
testAB
testAB
testABC
testABC
testABC

我么的本意是希望a、b、c是不变的,是相互独立的,结果却并不是我们期望的那样。
所以String不可变的安全性就体现在这里。
实际上StringBuffer的作用就是起到了String的可变配套类角色。

示例2

再看下面这个HashSet用StringBuilder做元素的场景,问题就更严重了,而且更隐蔽。

HashSet<StringBuilder> hs=new HashSet<>();
StringBuilder sb1 = new StringBuilder("aaa");
StringBuilder sb2 = new StringBuilder("aaabbb");
hs.add(sb1);
hs.add(sb2);    // 这时候HashSet里是{"aaa","aaabbb"}

StringBuilder sb3 = sb1;
sb3.append("bbb");  // 这时候HashSet里是{"aaabbb","aaabbb"}
System.out.println(hs);

控制台输出

[aaabbb, aaabbb]

StringBuilder型变量sb1和sb2分别指向了堆内的字面量aaa和aaabbb,并把它们插入到HashSet。
后面将sb1赋值给sb3,再改变sb3的值,因为StringBuilder没有不可变性的保护,
sb3直接在原先aaa的地址上改,导致sb1的值也变了。
这时候,HashSet上就出现了两个内容相等的字符串aaabbb。破坏了HashSet元素的唯一性。
所以千万不要用可变类型做HashMap和HashSet键

不可变性支持线程安全

在并发场景下,多个线程同时对一个资源进行写操作,会出现线程安全的问题。
而不可变对象不能被写,所以是线程安全的。

总结

Q:Java中String类为什么要设计成final?
A:.安全性、效率

  • 安全性:final类型的类不能被继承,并且String类中的final方法可以防止其内部的方法被重写,乱改。
  • 效率:final类型的类被JVM当作内联函数,提高了性能。

参考

在java中String类为什么要设计成final?

新手必看:5分钟搞定Unitree Go1机器狗Gazebo仿真运动控制(附按键图解) 本文为新手提供了Unitree Go1机器狗在Gazebo仿真环境中实现运动控制的快速指南。通过5分钟极简配置和按键图解,帮助开发者快速掌握宇树科技明星产品的基础操作,包括环境搭建、仿真启动和运动控制技巧,适合零基础用户快速上手。 阅读详情

相关推荐

Mathcad在LLC谐振变换器设计中的公式推导实战

本文通过Mathcad软件,详细演示了LLC谐振变换器设计的核心公式推导实战。文章阐述了如何利用Mathcad作为“会思考的草稿纸”,从定义基本参数、应用基波近似法(FHA)模型,到逐步推导电压增益公式及确定工作边界频率(fmin, fmax),并展示了如何通过动态参数扫描进行优化设计,帮助电源工程师高效、直观地完成理论计算,为后续仿真与实现奠定坚实基础。

q1w3e5r7t9y的博客 293

String为何是final的

String为何是final的百度答案我的答案新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 百度答案 1 主要是为了“效率” 和 “安全性” 的缘故。若 String允许被继承, 由于它的高度被使用率, 可能会降低程序的

zikailiu的博客 4099

视频生成工具本地部署完全指南:Seedance能装吗?有哪些开源替代?

本文系统介绍了视频生成模型的本地部署方案,分为三个部分:1)Seedance 2.0的混合部署模式,其开源组件可本地集成但核心功能需调用API;2)完全开源替代方案对比,包括LTX-2、Wan 2.1等模型的硬件需求与特点;3)详细部署指南,以ComfyUI+Wan 2.1为例,涵盖软件准备、模型整合、参数调优等步骤,并提供了显存优化和多GPU配置技巧。文章为需要离线视频生成能力的用户提供了完整技术路径。

小明的博客 1万+

String为什么要定义成final???

众所周知,String类在java.lang包中被定义成了final类型,那么这时候就有个疑问,为什么它要被定义为final呢?首先,我们先聊final修饰符的作用:...

wan25110712的博客 3253

从mseed到SAC格式转换全攻略:mseed2sac工具安装与批量处理技巧

本文详细介绍了如何将mseed格式的地震数据高效转换为SAC格式,涵盖mseed2sac工具的安装、单文件转换技巧、批量处理自动化实现以及元数据高级处理策略。通过具体命令和脚本示例,帮助地震学研究者快速掌握数据预处理的关键技术,提升波形数据分析效率。

ruby5的博客 927

MuJoCo 相机图片怎么拿?视角调整获取物体图片及实时显示(附代码)

在Mujoco的仿真中,对于识别抓取场景来说,如何获得添加的body等物体的实时图像很重要,今天就分享下如何添加相机视角及可视化小方块(举例)的实时图片。复制一个scene.xml为scene_withcamera.xml,在xml中添加camera和小方块如下。设置xml文件中添加的相机body id。需要创建一个离屏渲染器。

darcsdn 2128

为什么jdk中把String类设计成final?

最佳答案: 主要是为了“效率” 和 “安全性” 的缘故。若 String允许被继承, 由于它的高度被使用率, 可能会降低程序的性能,所以String被定义成final。 其它答案一: String和其他基本类型不同,他是个对象类型.既然是对象类型,如果是在静态方法下是必须调用静态方法或值的,如果是非静态的方法,就必须要实例化.  main函数是个static的.所以String要能像其他的

悲剧的程序猿 1339

【Unity】入门教程第一期-下载安装Unity编辑器(下)

讲解如何在Unity Hub中下载Unity编辑器以及IED环境

Xiaoxin的博客 2040

String为什么是final类

本文参考文章比较多,都是结合前辈们的思想整理来的,String为啥是final主要原因: 1.安全 string是不可变的,不管多少个线程来访问,字符串都不会发生改变; 2.HashCode string在创建是的时候会缓存hashCode,所以在map在用String做为key的时候可以直接用hashCode不用重新计算; 3.字符串常量池 ...

HDXxiazai的博客 455

基于TENG的呼吸测量与识别系统:从蓝牙到WiFi的改造与上位机实现

本文介绍了一种基于摩擦纳米发电机(TENG)的呼吸测量系统改造方案,将原有蓝牙通信升级为WiFi传输。系统通过TENG传感器采集呼吸信号,STM32微控制器处理数据后,经ESP8266 WiFi模块发送至上位机。文中详细阐述了硬件改造(四通道改单通道、蓝牙换WiFi)、嵌入式软件修改(包括ESP8266驱动、数据采集与TCP通信实现)以及上位机软件设计。改造后的系统提升了传输距离和稳定性,为可穿戴健康监测提供了更优解决方案。

huanghm88的专栏 110

如何使用Python爬取并保存网页上的所有附件

爬虫(Crawler)是一种自动化程序,它通过模拟人工访问网页并下载网页上的数据或文件,常用于数据采集和分析。爬虫通常以“爬取”的形式自动浏览和提取网页中的各种信息。本文详细介绍了如何使用Python爬取并保存网页中的附件文件,涵盖了网页解析、文件下载、多线程与异步优化等内容。希望通过本文的讲解,能够帮助你理解并掌握附件爬取的技巧。在实际应用中,爬虫开发不仅需要解决技术问题,还要遵守网络道德和法律法规,避免不当使用爬虫造成负面影响。

2201_76125261的博客 965

String类为什么是final类型?

String类为什么是final类型? 首先,先得清楚 final 这个关键字。 final的出现就是为了为了不想改变,而不想改变的理由有两点:设计(安全)或者效率。 final 修饰的类是不被能继承的,所以 final 修饰的类是不能被篡改的。 了解了这一点,我们再看看问题: 从设计安全上讲 确保它们不会在子类中改变语义。String类是final类,这意味着不允许任何人定义String的子类。 换言之, 如果有一个String的引用,它引用的一定是一个String对象,而不可能是其他类的对象。 Str

请叫我大师兄 4997

Cesium 实现动态加载气象数据:渲染成动态雨雪/云层效果(源码 + 原理)

本文介绍了在Cesium中实现动态天气效果的技术方案。核心思路是通过时间轴驱动多层数据动态切换,包括:1)时间维度处理,按序列加载不同气象图层;2)空间维度处理,将气象数据切分为瓦片;3)效果层实现,制作风场、降水等动态可视化效果。文章详细讲解了后端数据预处理(生成瓦片和风场JSON)、前端实现(双层雷达瓦片交替渐变、风场粒子系统)的具体方法,并提供了完整的代码示例。此外还探讨了雨雪粒子、云层效果等增强功能,以及工程化建议,为构建科学准确的动态天气可视化系统提供了实用解决方案。

专注AI大模型,软件混淆,授权 620

初级Java开发工程师!绝密文档,面试手册全面突击!!!秋招已经到来

这里我要明说一下,不是Java初级和学习Java的千万不要乱看,否则~~~~ 你会怀疑人生,因为会浪费你时间啊!!! 本次考点是Java初级开发工程师面试必备的一些东西!!! 1、数据类型 基本类型 byte/8、short/16、int/32、long/64、boolean/ 、char/16、float/32、double/64 boolean只有两个值,true、false,可以使用1bit来存储,但是具体大小没有明确规定,JVM会在编译时期将boolean类型转为int,使用1来表示true..

wj1314250的博客 1393

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Java面试突击:四层突击法攻克技术深度与系统设计

Java作为企业级应用开发的核心语言,其技术体系涵盖从基础语法到分布式架构的完整知识栈。理解Java内存模型、并发编程原理是构建高性能应用的基础,而JVM调优和MySQL索引优化则直接影响系统稳定性与扩展性。在微服务架构盛行的当下,掌握Spring框架的IoC容器、AOP机制以及事务管理原理,能够帮助开发者设计出更健壮的业务系统。通过HashMap并发安全、ThreadLocal内存泄漏等实际案例的分析,可以深入理解Java底层机制在电商秒杀、高并发订单等场景下的应用价值。本文基于Java集合框架性能对比和

weixin_30619101的博客 348

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

精准突击!2023最新版Java面试短期突击面试题【金典版】我会出手带你拿下Offer

面试题包括了:Java面试、Spring、MyBatis、ZK、Dubbo、EL、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题。177. 一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 MySQL 数据库,又插入了一条数据,此时 id 是几?164. kafka 同时设置了 7天和 10G 清除数据,到第五天的时候消息达到了 10G,这个时候 kafka 将如何处理?session与cookie的区别是什么?

BASK2311的博客 2931

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

【Java面试突击-1】Java基础(上)

基本类型 基本类型和包装类型 自动装箱与自动拆箱 自动装箱与自动拆箱的实现原理 哪些场景会自动装箱和拆箱 1,初始化和赋值 2,函数参数与返回值 3,基本数据放入集合中 4,包装类型与基本类型进行比较 5,三目运算符的使用 自动装拆箱的缓存机制 自动装箱与拆箱带来的问题 字符串 字符串的不可变性 怎么做到不可变的? String设计为不可变的好处 字符串拼接 字符串拼接方式 使用“+”拼接字符串 使用concat 使用StringBuffer 使用StringBuilder 使用StringUtils.jo

df007df的博客 810

Java面试突击指南:高频考点与实战策略

在软件开发领域,Java作为主流编程语言,其知识体系涵盖基础语法、并发编程、JVM调优、数据库优化及框架应用等多个核心模块。理解这些技术原理,对于构建高性能、高可用的分布式系统至关重要。从内存模型到垃圾回收机制,从索引优化到事务隔离,每一项技术都直接影响着系统的稳定性和效率。特别是在高并发场景下,如何保证数据的一致性和系统的响应速度,是工程师必须面对的挑战。本文聚焦于Java面试中的高频考点,如HashMap原理、volatile关键字、B+树索引及Spring事务机制,通过提炼核心知识脉络和实战代码示例,

weixin_33796177的博客 434

Java面试突击(一)Java基础考点--第一板块

这里主要是提供考题以供复习,具体答案可能后续公布。

weixin_46866349的博客 674

新鲜出炉!2020年最新java面试题大全,面试突击必备!

前言 发现网上很多Java面试题都没有答案,所以花了很长时间搜集整理出来了一套Java面试题,希望对大家有帮助哈~ 打算这几天每天更新15~20题。(这样有助于你们阅读和理解!)我们先从简单的开始 1. JDK 和 JRE 有什么区别? JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境。 JRE:Java Runtime Environment 的简称,java 运行环境,为 java 的运行提供了所需环境。 具体来说 JDK 其实包含了

欢迎您访问我的公众号【前程有光】 313

Java面试高效突击:一周掌握核心考点与场景串联法

在软件开发领域,掌握核心原理和高效学习方法是应对技术挑战的关键。从计算机科学基础概念出发,理解数据结构、算法和设计模式是构建复杂系统的基石。深入原理层面,例如理解JVM内存模型、并发编程的线程安全机制以及数据库的索引与事务隔离级别,能够帮助开发者编写高性能、高可用的应用。这些技术的价值在于解决实际工程中的性能瓶颈、数据一致性及系统扩展性问题,广泛应用于电商、金融等高并发场景。本文聚焦于Java技术栈,通过“场景串联法”和“高频问题树”等策略,将零散的知识点如并发编程中的volatile关键字和JVM调优中的

weixin_33701294的博客 394

【Java高频面试题大全集】Java 后端面试突击:20 道必问真题精讲(2)String 为什么不可变?有什么用?

String 为什么不可变?有什么好处?很多同学只会背:“因为 String 被 final 修饰”,但面试官一追问,就答不上来。这节课我给你最标准、最稳妥的回答。一、先讲:String 不可变的根本原因String 底层是被 final 修饰的 char 数组(JDK9 以后是 byte 数组)String 类本身也是 final 的,不能被继承没有提供任何修改数组内容的方法所以:String 对象一旦创建,值就不能改变。我们平时看到的字符串拼接、替换,其实都是新建了一个 String 对象,不是修改原来

gaochufukanyongren的博客 407

Java实习面试八股文怎么学?3天突击计划+答题框架

Java开发者备战实习面试,往往需要系统梳理编程基础与核心原理。理解集合框架、并发编程、JVM内存模型等底层概念,是提升技术敏感度和问题分析能力的关键。掌握HashMap的底层演化、线程池的参数调优、垃圾回收的执行机制等高频考点,不仅能应对面试提问,更能在实际项目中做出更优的技术选型与性能优化。将抽象理论还原为工程实践,通过清晰的答题逻辑和项目关联表达,才能让面试官快速认同你的技术潜力。本文提供一套3天高效突击方案,聚焦最常考的五大模块,配合可直接套用的答题框架,帮助读者在有限时间内抓住重点,从容应对Jav

优快云头条 1150

Java面试突击:从死记硬背到构建问题解决框架的高效策略

在软件开发领域,面试准备常被视为知识点的单向积累,但更本质的是信息的高效组织与检索能力。其核心原理在于构建一个结构化的知识索引系统,而非无限制地扩充记忆容量。这一方法的技术价值在于,它能将零散的技术概念(如Java内存模型、并发编程)串联成可推导的知识网络,从而在高压面试场景下实现快速、准确的响应。从应用场景看,无论是应对高频的JVM性能排查、MySQL索引优化,还是Spring框架的深度原理追问,构建以“母题”为核心、以“场景-技术-原理”为应答结构的学习框架,都能显著提升工程师的表达深度与问题拆解能力。

weixin_34228387的博客 361

金九银十Java面试突击:AI新考点与传统八股高效复习法

在技术招聘竞争愈发激烈的背景下,候选人需要一套高效的面试复习策略。传统的Java基础、集合、JVM、并发编程与Spring生态仍是核心考点,但随着AI大模型深入业务系统,RAG、Agent、Spring AI等新概念也频繁出现在面试中。理解这些技术的原理与应用场景,能够帮助工程师构建从基础原理到工程实践的知识体系。从大模型API调用、检索增强生成到智能体编排,技术栈的演进要求Java后端工程师具备快速整合新能力的方法。针对金九银十的求职窗口,通过筛选高频考点、强化场景题拆解和项目表达,可以极大提升面试通过率

weixin_33831196的博客 388

Java后端面试2周高效突击:核心考点与实战方案

Java并发编程是构建高并发应用的核心技术,其原理基于线程安全、锁机制和内存模型等基础概念。通过理解synchronized锁升级、volatile可见性等机制,开发者能够编写出高效可靠的多线程代码,这在分布式系统和秒杀场景中具有重要价值。HashMap作为Java集合框架的关键组件,其扩容机制和线程安全问题常出现在面试中,深入掌握有助于提升系统设计能力。本文聚焦金九银十招聘季,为Java后端开发者提供从技术基础到项目表述的全面突击方案,帮助快速提升面试竞争力。

weixin_34059951的博客 390
上一篇: 【JavaScript】巧妙利用对象解构,实现设置变量默认值或变量重命名
下一篇: 【Exception】Uncaught (in promise) Error: Redirected from “/xx” to “/yy” via a navigation guard
tanpenggood
博客等级 码龄9年 129粉丝 197原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值