初学JAVA时,在学习如何比较两个字符串是否相等,大量资料告诉我,不能用等于号( = )去比较,需要使用equals方法,理由是String是一个对象,等号此时比较的是两个字符串在java内存堆中的地址。

看下面代码:

String a = "abc";
String b = "abc";
System.out.println(a==b);

此时控制台打印的结果是:true

a和b是两个地址,==是地址的比较,a和b肯定是两个地址的,a==b为true呢?

这又是为什么呢?

求知欲驱使我一番搜索,以下摘抄自《深入理解JAVA虚拟机》:

运行时常量池(Runtime Constant Pool)是方法区的一部分。用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中

(众所周知,JDK1.8版本中,String常量池已经从方法区中的运行时常量池分离到堆中了,这本书是19年出版的,作者还是沿用旧版的描述。那么在堆中的String常量池里存的是String对象还是引用呢?)

运行时常量池具备动态性,运行期间也可以将新的常量放入池中,使用较多的便是String类的 intern()方法

《深入理解JAVA虚拟机》这本书的描述让人困惑,干脆直接看JDK源码里的intern方法。

 /**
* Returns a canonical representation for the string object.
* <p>
* A pool of strings, initially empty, is maintained privately by the
* class {@code String}.
* <p>
* When the intern method is invoked, if the pool already contains a
* string equal to this {@code String} object as determined by
* the {@link #equals(Object)} method, then the string from the pool is
* returned. Otherwise, this {@code String} object is added to the
* pool and a reference to this {@code String} object is returned.
* <p>
* It follows that for any two strings {@code s} and {@code t},
* {@code s.intern() == t.intern()} is {@code true}
* if and only if {@code s.equals(t)} is {@code true}.
* <p>
* All literal strings and string-valued constant expressions are
* interned. String literals are defined in section 3.10.5 of the
* <cite>The Java&trade; Language Specification</cite>.
*
* @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对象的字符串(用equals(oject)方法确定),则返回池中的字符串。否则,将此String对象添加到池中,并返回此String对象的引用。 对于任意两个字符串s和t,当且仅当s.equals(t)为true时,s.intern() == t.intern()才为true。

刚好有一篇文章:https://blog.csdn.net/weixin_39460458/article/details/79982765

他的问题完全一样,摘抄一段:

附:Java中两种创建字符串对象的方式的分析。

String s1 = "abc";
String s2 = "abc";
System.out.println(s1==s2);

结果是 true;

采用字面值的方式创建一个字符串时,JVM首先会去字符串池中查找是否存在"abc"这个对象,如果不存在,则在字符串池中创建"abc"这个对象,然后将池中"abc"这个对象的引用地址返回给"abc"对象的引用s1,这样s1会指向池中"abc"这个字符串对象;如果存在,则不创建任何对象,直接将池中"abc"这个对象的地址返回,赋给引用s2。因为s1、s2都是指向同一个字符串池中的"abc"对象,所以结果为true。

而:

String s3 = new String("xyz");
String s4 = new String("xyz");
System.out.println(s3==s4);

结果是 false

采用new关键字新建一个字符串对象时,JVM首先在字符串池中查找有没有"xyz"这个字符串对象,如果有,则不在池中再去创建"xyz"这个对象了,直接在堆中创建一个"xyz"字符串对象,然后将堆中的这个"xyz"对象的地址返回赋给引用s3,这样,s3就指向了堆中创建的这个"xyz"字符串对象;如果没有,则首先在字符串池中创建一个"xyz"字符串对象,然后再在堆中创建一个"xyz"字符串对象,然后将堆中这个"xyz"字符串对象的地址返回赋给s3引用,这样,s3指向了堆中创建的这个"xyz"字符串对象。s4则指向了堆中创建的另一个"xyz"字符串对象。s3 、s4是两个指向不同对象的引用,结果当然是false。

自己试了一下:

回到开头的结论是:java代码编译成class文件时,JVM自己优化了,此时b的地址指向a,所以a==b打印结果是true

深入理解JAVA字符串常量池的更多相关文章

  1. 理解Java字符串常量池与intern()方法

    String s1 = "Hello"; String s2 = "Hello"; String s3 = "Hel" + "lo ...

  2. Java字符串常量池及字符串判等解析

    一.理解"=="的含义 "=="常用于两个对象的判等操作,在Java中,"=="主要有以下两种用法: 1.基础数据类型:比较的是他们的值是否 ...

  3. Java字符串常量池是什么?为什么要有这种常量池?

    简单介绍 Java中的字符串常量池(String Pool)是存储在Java堆内存中的字符串池.我们知道String是java中比较特殊的类,我们可以使用new运算符创建String对象,也可以用双引 ...

  4. java字符串常量池——字符串==比较的一个误区

    转自:https://blog.csdn.net/wxz980927155/article/details/81712342   起因 再一次js的json对象的比较中,发现相同内容的json对象使用 ...

  5. Java字符串常量池

    JVM为了减少字符串对象的重复创建,维护了一个特殊的内存,这段内存被称为字符串常量池. Java中字符串对象的创建有两种形式:一种是字面量形式,String str = "a":一 ...

  6. 关于java字符串常量池

    今天发现一个好玩的东西 public static void main(String[] args)    {        String str1 = new StringBuilder(" ...

  7. 看完肯定懂的 Java 字符串常量池指南

    字符串问题可谓是 Java 中经久不衰的问题,尤其是字符串常量池经常作为面试题出现.可即便是看似简单而又经常被提起的问题,还是有好多同学一知半解,看上去懂了,仔细分析起来却又发现不太明白. 背景说明 ...

  8. [JAVA]字符串常量池String pool

    字符串常量池(String Pool)保存着所有字符串字面量(literal strings),这些字面量在编译时期就确定.不仅如此,还可以使用 String 的 intern() 方法在运行过程中将 ...

  9. java——字符串常量池、字符串函数以及static关键字的使用、数组的一些操作函数、math函数

    字符串常量池: 字符串比较函数:  字符串常用方法:  字符串截取函数: 字符串截取函数:  static关键字使用: 要调用类中的static类型的变量的时候,可以用"类名.变量名&quo ...

随机推荐

  1. Catalan数应用问题

  2. String.slice

    String.slice(start, end)start从字符串的哪个index开始截取 默认值0 如果为负值,则从字符串的尾部向前倒推indexend到从字符串的哪个index结束截取 默认值st ...

  3. JAVA SE Lesson 1

    1.  类是一种抽象的概念,对象是类的一种具体表示形式,是具体的概念.先有类,然后由类来生成对象(Object).对象又叫做实例(Instance).2.  类由两大部分构成:属性以及方法.属性一般用 ...

  4. LLDB奇巧淫技

    打印视图层级 这个相信很多人都会了,是ta是ta就是ta recursiveDescription 用法大概就是如下 123 po [self.view recursiveDescription] p ...

  5. 未来京东真能成为中国第一大B2C电商平台吗?

    ​     2月10日,京东集团在北京举行2017年"科技引领未来"开年年会.在本届年会上,京东宣布全面向技术转型.京东集团CEO刘强东正式对外公布未来12年的战略:在以人工智能为 ...

  6. webpack环境配置2

    1.webpack安装 Step 1: 首先安装Node.js, 在1中已经详细介绍了. Step2: 在Git或者cmd中输入下面这段代码, 通过全局先将webpack指令安装进电脑中npm ins ...

  7. 致敬尤雨溪,Vue.js 让我赚到了第一桶金

    最近这个 Vue.js 纪录片在前端圈广为传播,相信不少人已经看过了.第一次看编程领域的纪录片,感觉还挺新鲜的.这部 30 分钟左右的纪录片制作精良,主角是 Vue.js 作者尤雨溪,还穿插采访了框架 ...

  8. Solr查询配置及优化【eDisMax查询解析器】

    一.简介 Lucene查询解析器语法支持创建任意复杂的布尔查询,但还有一些缺点,它不是用户查询处理的理想解决方案.这里面最大的问题是Lucene查询解析器的语法要求严格,一旦破坏就会抛出异常.指望用户 ...

  9. Spring Boot 2.x基础教程:使用 ECharts 绘制各种华丽的数据图表

    上一节我们介绍了如何在Spring Boot中使用模板引擎Thymeleaf开发Web应用的基础.接下来,我们介绍一下后端开发经常会遇到的一个场景:可视化图表. 通常,这类需求在客户端应用中不太会用到 ...

  10. py基础之无序列表

    '''dic是一个可以将两个相关变量关联起来的集合,格式是dd={key1:value1,key2:value2,key3:value3}'''d = { 'adam':95, 'lisa':85, ...