正常情况

如果按照正常情况,你面试的时候,看到这个代码,你肯定会说:结果是false。

如果我要他们是true,应该怎么做呢?有什么方法吗?

  String str4 = new String("abc");String str5 = new String("abc");System.out.println((str4 == str5));//false

因为上面的代码会在堆区(heap),存入两个不同的对象。所以,直接使用双等号==的结果肯定是false的。

但是,JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化:

  • 为字符串开辟一个字符串常量池,类似于缓存区

  • 创建字符串常量时,首先查询字符串常量池是否存在该字符串

  • 存在该字符串,返回引用实例;不存在,实例化该字符串并放入池中

那么,我们是否可以直接利用常量池里面的字符串呢?

看看这段代码

  String str1 = "abc";String str2 = "abc";String str3 = "abc";String str4 = new String("abc");String str5 = new String("abc");String str6 = new String("abc");

使用上面的代码画了一个简易示意图

从图中,可以看出最开始的String str1 = "abc"; ,str1直接引用常量池的实例,步骤应该是,先从常量池里面找一下,发现没有"abc",然后,新建了一个全局唯一并且不可变的"abc"字符串常量放进常量池。

那么,我们思考一下:
既然知道常量池里面有一个"abc",为啥不能利用他呢?如果我做到str4 和 str5能拿到常量池里面的"abc"这不就能使用双等号==进行比较了吗?

按照常量池这个理论去推算:我们可以做个假设,如果我双等号==比较的是常量池中的"abc",这样子不就会是true了吗?

那么,我们现在的主攻解决方向就是:
如何让str4 和 str5 得到常量池中唯一的"abc"呢?

如何获得常量池中的值?

我们可以使用String的intern()方法,请查看JDK源码解释:

/*** Returns a canonical representation for the string object.* <p>* A pool of strings, initially empty, is maintained privately by the* class <code>String</code>.* <p>* When the intern method is invoked, if the pool already contains a* string equal to this <code>String</code> object as determined by* the {@link #equals(Object)} method, then the string from the pool is* returned. Otherwise, this <code>String</code> object is added to the* pool and a reference to this <code>String</code> object is returned.* <p>* It follows that for any two strings <code>s</code> and <code>t</code>,* <code>s.intern()&nbsp;==&nbsp;t.intern()</code> is <code>true</code>* if and only if <code>s.equals(t)</code> is <code>true</code>.* <p>* All literal strings and string-valued constant expressions are* interned. String literals are defined in &sect;3.10.5 of the* <a href="http://java.sun.com/docs/books/jls/html/">Java Language* Specification</a>** @return  a string that has the same contents as this string, but is*          guaranteed to be from a pool of unique strings.*/public native String intern();

用人话说就是:
当调用intern方法时,如果常量池中已经含有相同内容的String实例,就返回常量池中这个相同内容的String实例

那么,我们就用intern方法测试一下:

  String str4 = new String("abc");String str5 = new String("abc");System.out.println("(str4 == str5):"+(str4 == str5));System.out.println("(str4.intern() == str5.intern()):"+(str4.intern() == str5.intern()));

测试结果截图:

说明了他们确实使用了常量池中的String对象,因为常量池中的"abc"是唯一的,所以,他们返回的同一个引用,所以,使用双等号==比较的结果是true。

知道之后,又能干什么呢?

相信读到这里, 你对于String的常量池有更加深的理解,而不是停留在面试题上的String str4 = new String("abc");这里创建了几个对象这种背诵式的应答。

而是,可以用更深层次去回答面试官,用代码例子去证明有多少个对象!!!

面试题:下面的代码产生多少个String对象呢?(请用代码证明)

//面试题:下面的代码产生多少个String对象呢?
//请用代码证明有多少个对象public static void main(String[] args) {String str4 = new String("abc");System.out.println("(str4 == \"abc\"):"+(str4 == "abc"));System.out.println("(str4.intern() == \"abc\"):"+(str4.intern() == "abc"));}===============================================
测试截图:
(str4 == "abc"):false
(str4.intern() == "abc"):true

项目上的实战应用

除了可以加深理论知识的理解之外,还可以应用于实战。

相信大家都用过synchronized 同步代码块,请仔细看下面代码中的注释说明

  • Book book = dao.get(bookId);//假设每次查询bookId,都不使用缓存对象,每次都从DB里面直接拿出来

  • 这样子就会就算bookId相同,对象也是不同的。

  • 那么,如果多线程情况,不同线程都要查询同一个bookId呢?

    Book book = dao.get(bookId);//这样子就会就算bookId相同,对象也是不同的。//那么,如果多线程情况,不同线程都要查询同一个bookId呢?synchronized (book) {//坑货,bookId相同的Book也进来了,你的锁又有什么意义呢?}

因为就算是相同的bookId返回的都是两个不同的Book对象。所以,就算使用了synchronized 同步代码块也是没有意义的,因为是两个不同的对象,这样子是没有起到锁的作用,会是并行的执行结果。这样就不是我们想要的!!!

我们的目的是让相同的bookId的对象串行互斥执行代码,保证安全。而不同的bookId,是可以同时并行去执行,不影响不同的bookId的Book对象进行计算。

这个时候,常量池的String对象就很有用了,因为常量池的String对象是全局唯一的,所以,你不管你拿到多少次常量池的对象,其实,都是同一个对象。既然是同一个对象,那么,对这个唯一对象加锁,就可以做到加锁效果了。

改进代码如下:

    Book book = bookService.get(bookId);String currBookId = book.getId();    synchronized (currBookId.intern()) {//为了简洁减少代码就不进行null判断啦!//这样子就可以做到相同bookId无法进来,又不会挡住不同bookId进行自己的操作,并行处理不同的Book了}

最后

大家现在是不是感觉对于String常量池可以看得到,摸得着了。而不会再机械式回答面试题了,不会再不知所以然了。

其实,面试官问你String str4 = new String("abc"); 产生多少个String实例,不是真的叫你用手指去数,而是,考察你平常对基础理论的认知,考察你对问题思考的深度,而不是停留在面试题规范答案的表面。

你试想一下,
如果你是面试官,应聘者用代码层面去讲解常量池,是不是比千篇一律的规范式回答会加分呢?

课后作业

看完这篇文章,你真的懂了吗?
要不,测试一下你是否理解透彻了?

//请看题:String s1 = "123";String s2 = new String("123");Long number1 = 123L;String s3 = new String("true");Boolean boolVal = true;System.out.println("Q1:"+(s1 == s2));System.out.println("Q2:"+(s1 == s2.intern()));System.out.println("Q3:"+(s1.intern() == s2));System.out.println("Q4:"+(s1.intern() == s2.intern()));System.out.println("Q5:"+(number1.toString() == s1));System.out.println("Q6:"+(number1.toString().intern() == s1));System.out.println("Q7:"+(s3 == boolVal.toString()));System.out.println("Q8:"+(s3.intern() == boolVal.toString()));System.out.println("Q9:"+(s3.intern() == boolVal.toString().intern()));System.out.println("Q10:"+(s2.intern() == boolVal.toString().intern()));

想看看自己是否全部答对了?
可以在微信公众号里面回复:String123
就可以查询到这一题答案。你真的能全部答对吗?

哈哈,未必!

怎么做到new String(abc) == new String(abc)双等号为true呢?不是使用equals哦相关推荐

  1. 云端飘 String s=new String(abc)创建了几个对象?

    转自:http://www.cnblogs.com/ydpvictor/archive/2012/09/09/2677260.html -------------------------------- ...

  2. String str =new String(“abc“)和 String str = “abc“的比较

    String是一个非常常用的类,应该深入的去了解String 如: String str =new String("abc") String str1 = "abc&qu ...

  3. String s=new String(abc)创建了2个对象的原因

    问题:String str=new String("abc"); 这行代码究竟创建了几个String对象呢? 相信大家对这道题并不陌生,答案也是众所周知的,2个. 接下来我们就从这 ...

  4. java s1=abc s2=abc s1==s2_经典问题:String s1 = abc 与 String s2 = new String(abc)的区别...

    这是以前刚学Java那会经常被问到的问题,并且也会经常出现在面试中.这个问题不仅仅只局限于Java,可以适用于其他大部分语言,正好最近有个小朋友在学编程,特此整理一下. String s1 = &qu ...

  5. String s1=new String(“abc“); 和String s1=“abc“区别

    在讨论他们的区别时,我们要知道java中的内存,主要分为堆和栈.栈中一般存放的是java中的基本数据变量 比如 int,double,float 还存放了对象的引用变量 如 Person person ...

  6. String str = new String(abc)创建了几个对象?结合源码解析

    String str = new String("abc")创建了几个对象?结合源码解析 首先,我们看一下jdk源码: 1 /** 2 * Initializes a newly ...

  7. java中String s=abc及String s=new String(abc)详解

    java中String s="abc"及String s=new String("abc")详解 1.   栈(stack)与堆(heap)都是Java用来在R ...

  8. Java:面试题:String s=new String(abc)创建了几个对象?

    String str=new String("abc");   紧接着这段代码之后的往往是这个问题,那就是这行代码究竟创建了几个String对象呢? 相信大家对这道题并不陌生,答案 ...

  9. String a =new String(“abc”);和String b=”abc”;的区别

    看图有助于理解: String a =new String("abc")实际上是创建了两个对象(假设之前String的常量池中没有创建任何对象),一个是"abc" ...

最新文章

  1. es6 新增数据类型Symbol
  2. CentOS 7 使用iptables 开放端口
  3. 中国健康体检行业行情动态及未来发展趋向分析报告2022年版
  4. Kettle使用_27 行转列与列转行方法汇总
  5. SPOJ 962 Intergalactic Map (从A到B再到C的路线)
  6. 罗技 连点 脚本_罗技推出多款《英雄联盟》联名外设 看了就忍不住想要
  7. 【重难点】【RabbitMQ 02】如何避免消息重复投递和消息重复消费、如何防止消息丢失、如何保证消息的顺序性、如何保证消息队列的可用性
  8. python 中的 __name__
  9. MATLAB 线性运算之图像相加去噪
  10. flask before_request after_request
  11. 域名访问html乱码,显示地址和域名解析时出现乱码
  12. springboot使用@Async实现异步操作
  13. Unix操作系统基础:Unix文件系统之文件权限
  14. 【Selenium Grid 分布式测试】Selenium Grid下载安装
  15. 开心网刷分程序详解以及web游戏破解思路分析(一)
  16. 2407 · 计算 a + aa + aaa + aaaa 的值(LintCode,Python,入门)
  17. 光滑的圆环(glossy torus)
  18. 登录页面(动态背景)
  19. 北京上市公司招聘.net架构师及开发人员
  20. 怎样将文件后缀名统一重命名并为大写字母

热门文章

  1. oracle 云服务免费申请
  2. el-table 固定表头,固定列,动态高度,最简单的办法
  3. 动画(Animation)来回变换
  4. VS2015制作服务程序安装包
  5. 还有猛料?维基解密称只发布了已掌握美中情局文件的1%
  6. win10备份为wim_Win10 也能玩转一键还原
  7. 美丽乡村——大堰镇南溪村
  8. N880e 刷机记录和一些经验
  9. w ndows默认截图工具,浅谈Win10系统下截屏方式
  10. 同济大学Python程序设计基础 实验九:数据可视化