基础面试,为什么面试官总喜欢问String?
关于 Java String,这是面试的基础,但是还有很多童鞋不能说清楚,所以本文将简单而又透彻的说明一下那个让你迷惑的 String

在 Java 中,我们有两种方式创建一个字符串
String x = "abc";
String y = new String("abc");
你常见也常写第一种,很少见第二种,但面试还总问这类问题,双引号和构造器两种形式创建字符串到底有什么差别呢?
先来看例子
例子 1
String a = "abcd";
String b = "abcd";
System.out.println(a == b); // True
System.out.println(a.equals(b)); // True
a == b 结果为 true,是因为 a 和 b 都指向 方法区(method area) 同一个字符串文字,内存引用是同一个
当多次创建相同的字符串文字时,只存储每个不同字符串值的一个副本。这个叫做字符串留驻/留用,Java 中所有编译期字符串常量都会被自动留驻
例子 2
String c = new String("abcd");
String d = new String("abcd");
System.out.println(c == d); // False
System.out.println(c.equals(d)); // True
c==d 结果为 false,因为 c 和 d 的引用指向堆中不同的对象,不同的对象肯定有不同的内存引用
举了两个例子,文字描述有点懵?我们来试图通过图形来理解上述两种情况:

也许你已经看看出来了,一个是在方法区,一个是在堆中,在 JVM 模型中这是两个不同的区域,也许你面试时也经常被问到吧,来看下图:

再次提醒一下,所有 new 的对象都会在 Heap 中,这样以后你就好区分了
运行期字符串留驻
上面说的字符串留驻是在编译期,那么运行期可以吗?答案是肯定的,我们需要一个函数来帮忙
String c = new String("abcd").intern();
String d = new String("abcd").intern();
System.out.println(c == d); // Now true
System.out.println(c.equals(d)); // True
看到 c == d 结果为 true,你应该理解 intern (英文有拘留,软禁的意思)的作用了,通过调用 intern()方法,就好比把创建的字符串拘留在方法区一样了
在面试时甚至还会问你下面代码创建了几个对象:
String d = new String("abcd")
- 如果方法区已存在"abcd", 那么只创建一个 new String 的对象
- 如果方法区没有"abcd", 那么要创建两个对象,一个在方法区,一个在堆中
所以,正常情况下我们没必要使用构造器创建对象,因为这很可能会产生一个额外的没用的对象,但是有例外哦,我们下面说
String s = "abcd";
s = s.concat("ef");

当我们想在字符串 s 后面拼接字符"ef"时,会在堆中创建一个新的对象,并将 s 的引用指向新创建的对象,由于 String 创建的是不可变对象,所以 String 类中的所有方法都不会改变它自身,而是返回一个新的字符串(快打开你的 IDE,看看是否每个操作String 的方法最后都是返回有 return new String 字样),到这里你也应该理解了一个道理:
如果我们需要一个字符串被修改,我们最好使用 StringBuffer 或者 StringBuilder,否则,由于每次操作字符串都会创建一个新的对象,而旧的对象不会有引用指向它,这样我们会浪费很多垃圾回收的时间
到这里还没完,你有没有想过为什么 String 会被设置/制造成 final?
为什么 String 类被 final 修饰
谈及这个问题我们需要一些倒推的或者相互约束思维来思考
字符串池的需求
字符串池(String intern pool)是方法区域中的一个特殊存储区域。当创建一个字符串时,如果该字符串已经存在于池中,那么返回现有字符串的引用,而不是创建一个新对象。所以说,如果一个字符串是可变的,那么改变一个引用的值,将导致原本指向该值的引用获取到错误的值
缓存 hashcode
字符串的hashcode在Java中经常使用。例如,在HashMap或HashSet中。不可变保证hashcode始终是相同的,这样就可以在不担心更改的情况下兑现它。这意味着,不需要每次使用hashcode时都计算它。这样更有效率。所以你会在 String 类中看到下面的成员变量的定义:
/** Cache the hash code for the string */
private int hash; // Default to 0
安全性
String被广泛用作许多java类的参数,例如网络连接、打开文件等。如果字符串不是不可变的,连接或文件将被更改,这可能导致严重的安全威胁。该方法认为它连接到一台机器上,但实际上并没有。可变字符串也可能导致反射中的安全问题,因为参数是字符串。
不可变对象天生是线程安全的
由于不可变对象不能被更改,所以它们可以在多个线程之间自由共享。这消除了同步的需求。
总之,出于效率和安全性的考虑,String 被设计为不可变的。这也是为什么在一般情况下,不可变类是首选的原因。
附加说明
关于不可变对象和不可变引用总是有同学搞不清楚
final User user = new User();
上面的代码指的是 user 引用不能被更改指向内存的其他地址,但是由于 User 是可变对象,我们可以调用 user 的 setter 方法修改其属性
在String类中包含很多学问,包括你对JVM模型的理解,这也就是为什么面试官为什么喜欢问String,主要考察你的基本功
灵魂追问
- String 和基本类型的包装类如 Integer 和 Long 都被 final 修饰,但为什么不建议作为 synchronized 同步块的参数适用呢?
- 基本类型自动装箱你知道发生了什么吗?和上一个问题有关系
提高效率工具

Material Theme UI
这是一款 IDEA 的主题插件,安装后,选择 Material Palenight 主题,同时作出如下设置

设置完后,你的 IDEA 就是下面这样,引起极度舒适

推荐阅读
- 每天用SpringBoot,还不懂RESTful API返回统一数据格式是怎么实现的?
- 双亲委派模型:大厂高频面试题,轻松搞定
- 面试还不知道BeanFactory和ApplicationContext的区别?
- 如何设计好的RESTful API
- 红黑树,超强动静图详解,简单易懂
欢迎持续关注公众号:「日拱一兵」
- 前沿 Java 技术干货分享
- 高效工具汇总 | 回复「工具」
- 面试问题分析与解答
- 技术资料领取 | 回复「资料」
以读侦探小说思维轻松趣味学习 Java 技术栈相关知识,本着将复杂问题简单化,抽象问题具体化和图形化原则逐步分解技术问题,技术持续更新,请持续关注......

基础面试,为什么面试官总喜欢问String?的更多相关文章
- 一线大厂面试官最喜欢问的15道Java多线程面试题
前言 在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分.如果你想获得更多职位,那么你应该准备很多关于多线程的问题. 他们会问面试者很多令人混淆的Java线程问题.面试官只是想确信面试者 ...
- 2019年面试官最喜欢问的28道ZooKeeper面试题
前言 ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务.它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护.域名服务.分布式同步.组服务等. ZooKeeper 的 ...
- 深度分析:面试腾讯,阿里面试官都喜欢问的String源码,看完你学会了吗?
前言 最近花了两天时间,整理了一下String的源码.这个整理并不全面但是也涵盖了大部分Spring源码中的方法.后续如果有时间还会将剩余的未整理的方法更新到这篇文章中.方便以后的复习和面试使用.如果 ...
- 聊聊CAS - 面试官最喜欢问的并发编程专题
什么是CAS 学习Java并发编程,CAS(Compare And Set)机制都是一个不得不掌握的知识点.除了通过synchronized进行并发控制外,还可以通过CAS的方式控制,大家熟悉的Ree ...
- 阿里面试官最喜欢问的21个HashMap面试题
1.HashMap 的数据结构? A:哈希表结构(链表散列:数组+链表)实现,结合数组和链表的优点.当链表长度超过 8 时,链表转换为红黑树. transient Node<K,V>\[\ ...
- 2021超详细的HashMap原理分析,面试官就喜欢问这个!
一.散列表结构 散列表结构就是数组+链表的结构 二.什么是哈希? Hash也称散列.哈希,对应的英文单词Hash,基本原理就是把任意长度的输入,通过Hash算法变成固定长度的输出 这个映射的规则就是对 ...
- 走向DBA[MSSQL篇] 面试官最喜欢的问题 ----索引+C#面试题客串
原文:走向DBA[MSSQL篇] 面试官最喜欢的问题 ----索引+C#面试题客串 对大量数据进行查询时,可以应用到索引技术.索引是一种特殊类型的数据库对象,它保存着数据表中一列或者多列的排序结果,有 ...
- 面试总被问分布式ID怎么办? 滴滴(Tinyid)甩给他
整理了一些Java方面的架构.面试资料(微服务.集群.分布式.中间件等),有需要的小伙伴可以关注公众号[程序员内点事],无套路自行领取 一口气说出 9种 分布式ID生成方式,面试官有点懵了 面试总被问 ...
- Java面试官最常问的volatile关键字
在Java相关的职位面试中,很多Java面试官都喜欢考察应聘者对Java并发的了解程度,以volatile关键字为切入点,往往会问到底,Java内存模型(JMM)和Java并发编程的一些特点都会被牵扯 ...
随机推荐
- 数组中重复的数字(剑指offer_3)
在一个长度为n的数组里的所有数字都在0到n-1的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的,也不知道每个数字重复几次.请找出数组中任意一个重复的数字. Input: {2,3,1,0 ...
- 数组累计-reduce
reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值. reduce() 可以作为一个高阶函数,用于函数的 compose. array.reduce(f ...
- CSP2019 游记
\(\text{CSP 2019}\) 游记 \[\text{草}\] \[\text{By:Luckyblock}\] \[Day\ -1:\] \(19:00\) 送行饭, 被摁在墙角干了 因为偏 ...
- ReactNative: 使用Touchable触摸类组件
一.简介 在应用程序中,最灵魂的功能就是交互.通过给应用程序的组件添加事件来实现交互,进而提高用户体验.然而,ReactNative并不能像Web开发那样可以给大多数的标签元素绑定click事件,例如 ...
- 如何获取JVM堆转储文件
堆转储是诊断与内存相关的问题(例如内存泄漏缓慢,垃圾回收问题和 java.lang.OutOfMemoryError.它们也是优化内存消耗的重要工具. 有很多很不错的的工具,例如Eclipse MAT ...
- Vue-element-admin实现菜单根据用户权限动态加载
之前有一些网友对我那个IT部门信息管理系统(http://caijt.com/it)的前端感兴趣,我已经开源到github(https://github.com/Caijt/itsys-ui) 上面有 ...
- PHP给图片加上图片水印和文字水印实例
下面给大家分享一下PHP给图片加上图片水印和文字水印实例,这也是网站经常用到的功能,把代码加上去,调用就很简单了. 核心代码: function imageWaterMark($groundImage ...
- Thymeleaf常用语法:使用星号表达式
在处理模板时,一般情况都是使用变量表达式 ${...} 来显示变量,还可以使用选定对象表达式 *{...},它也称为星号表达式.如果在模板中先选定了对象,则需要使用星号表达式.Thymeleaf的内置 ...
- requests---requests上传图片
我们在做接口测试的时候肯定会遇到一些上传图片,然后进行校验,今天我们一起学习通过requests上传图片,查看是否上传成功 抓取上传接口 这里我以百度为例子进行操作,为啥要用百度呢,主要上传文件比较简 ...
- August 04th, 2019. Week 32nd, Sunday
Making peace with what you don't have, that's what it's all about. 人生在世,不如意者十之八九,保持平常心,命里无时莫强求. Ever ...