概述
对于字符串String的学习一直是迷迷糊糊,但这块知识却也是重点,要想真正的搞懂不仅要清楚的知道Java中的内存模型,也要能准确区分各种创建好的对象的存储位置。在自己看了深入理解Java虚拟机这本书后,结合多篇博客,才感觉稍微入门,用这篇博客总结记录一下自己理解下的字符串常量池。
String
一、关于String类
之前写过关于String类的简单认识—>字符串String类可供参考
二、常量池
关于Java内存模型参照—>Java虚拟机中的内存区域
这里再着重说一下常量池的概念。运行时常量池和字符串常量池之间有什么关系呢?
在Java虚拟机中常见的几种常量池:class文件常量池、运行时常量池、字符串常量池
Class文件常量池:主要运用编译时期产生的字面量和符号引用
其中,字面量类似常量包括String类型的值和final修饰的变量。
运行时常量池:Class文件会在类加载后进入方法区,就称之为运行时常量池
字符串常量池:在jdk1.6时,字符串常量池就存在与方法区中,在jdk1.7版本后,字符串常量被移到了堆中。因此1.7版本后,字符串常量池就没有存在于运行常量池中了。
接下来,让我们看一段代码:
三、代码分析
让我们看看下面一段代码中的问题:
问题一:
这里是否相等相信困扰着许多人。在我们判断时,重点是要理解上面的例子中每一种方式对象创建的位置。
直接创建时(例如创建s1)时,如同上面介绍的常量池的概念,将会在编译期间就生成出
“abc”这个字面常量。每次使用直接创建时,至少会产生0个对象,至多产生1个对象。原因是:如果在字符串常量池中已经有了相同的字面量的对象,那么再次创建时将直接引用该对象,反之如果常量池中不存在,就会在常量池中创建一个对象。
第二就是使用String类的new()方法创建(例如s2),此种方式下,至少会产生1个至多会产生2个对象。原因是:使用new方法是一定会在堆上创建一个对象的,另外由于new()的字面量也会在编译时在常量池中创建一份,但如果在创建时,常量池中已经有了相同的字面量,就不会再次创建。
例如以下四种:
第三种是字面量直接相加(例如s4)这种情况下,编译器会直接进行优化,将两个字面量相加后的结果作为一个整体进行创建,此时就类似s1的直接创建,只在常量池中寻找是否已经存在相同的字面量,有则引用,没有则创建。
第四种仍然是相加,只是相加的是两个new()出来的String类对象(例如s5、s8其实均是此种方式),在这种方式下,采用的是动态调用,会类似s2的创建重新new一个对象出来,而最终的结果不作为字面常量。
第五种就是使用已有String对象的intern()方法(例如s9),在这种情况下,首先会在常量池中搜索是否已经有于该字面量相同的对象,如果有,则返回该对象,如果没有,则在常量池中重新创建。
接下来,我们针对问题进行分析:
好,这个明白了那再来看下一个问题:
问题二:
这个问题事实上还是上面问题的延申,现在来分析一下:
为什么s10和s11不相等呢?intern方法起作用了吗?
首先第一句代码执行,在堆上创建一个对象,s10指向堆上的对象。接着直接在常量池创建s11返回地址给s11。此时对s10调用intern方法,发现常量池中已经有了该字面量,就不再创建,而是返回s10在常量池中的引用地址也即返回s11的引用,但没有接收的变量,如果使用变量接受再比较接受结果的变量和s11,返回值就是true。但在当前情况下s10在堆,s11在常量池,自然不相等。
那么类比下面的代码呢?
为什么此时返回的就是true呢?
原因是,在s12创建好后,常量池中存在“hello”“world”但并不存在“hello world”字面量,在执行intern方法后在常量池中查找,找到返回引用,找不到就创建,jdk1.7以后在常量池中创建后,常量池中保存的是s12的引用,因此当创建s13时,在常量池中查找后,返回的是s12这个引用。两个相同的引用一定是返回true的。故此时intern方法对代码块有影响。
只是交换了intern方法的位置就可能会产生不同的结果。
Integer
像Integer这种包装类,只要创建就会消耗资源,因此,Java对各种包装类在[-128 - 127]之间是会放到常量池中,而超过这个范围就会创建对象。
但是Float和Double类型没有实现常量池技术。
包装类的“==”运行符在不遇到算术运算的情况下不会自动拆箱,以及他们的equals()方法不处理数据类型的关系
Long的equals方法会先判断是否是Long类型
无论是Integer还是Long,他们的equals方法比较的是数值
通过例子来看:
问题三:
现在逐一来分析:
c==d
因为c、d均在[-128-127]范围内,故在均常量池中。此时没有遇到运算符,不自动拆箱比较的是引用是否是指向同一个对象,而不是数值。
e==f
e、f 均不在[-128-127]范围内,因此在堆上创建对象,此时无论对象的值是否相等,由于不是同一个引用故返回false
c == (a+b)
由于包装类遇到了运算符,就进行了自动拆箱,此时比较的就是对象里面的value属性值是否相等,故返回true
c.equals(a+b)
无论是Integer还是Long,equals方法比较的是数值是否相等,故返回true
f == g
int和Integer相比较也会对包装类自动拆箱,因此比较的还是值的大小,故返回true
h == (a + b)
由于包装类遇到了运算符,就进行了自动拆箱,此时比较的就是对象里面的value属性值是否相等,故返回true
h.equals(a + b)
Long类型的equal在比较时,会先判断a+b是否为Long类型,显然a+b不是,因此false
————————————————
原文链接:https://blog.csdn.net/Moo_Lavender/article/details/103198617
最后
以上就是丰富白猫为你收集整理的integer判断是否为空_String和Integer分配内存的分析String一、关于String类二、常量池三、代码分析为什么s10和s11不相等呢?intern方法起作用了吗?为什么此时返回的就是true呢?Integer的全部内容,希望文章能够帮你解决integer判断是否为空_String和Integer分配内存的分析String一、关于String类二、常量池三、代码分析为什么s10和s11不相等呢?intern方法起作用了吗?为什么此时返回的就是true呢?Integer所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复