Java内存分析中,我们会经常听到关于“常量池”的描述,实际上常量池也分了以下三种:全局字符串常量池、class 文件常量池、运行时常量池(Runtime Constant Pool)。我们只关注常量池(Runtime Constant Pool)即可。
线程有线程池来管理,而常量池就是为了来管理字符串的,所以这里必须要先熟悉String类。
相关网址:
Java String类(超级详细!)_长头发的程序猿的博客-CSDN博客
先看一段代码:
- package org.example.test;
-
- public class PoolTest {
- public static void main(String[] args) {
- String s1 = "程序猿你好!!!";
- String s2 = "程序猿你好!!!";
- String s3 = new String("程序猿你好!!!");
-
- System.out.println(s1 == s2);
- System.out.println(s1 == s3);
- System.out.println(s1.equals(s3));
- }
- }
运行结果:
下面我们来逐条分析:
能来研究JVM的常量池的程序猿们肯定知道”==“比的是两个对象的内存地址,那么为什么“s1 == s2"的输出结果为true呢?
分析:
这就是常量池的原因,常量池它本身是一种管理字符串的机制,当我们执行“String s1 = "程序猿你好!!!";”时,jvm就会在常量池中开辟一块空间来存放s1,当执行到“String s2 = "程序猿你好!!!";”时,jvm就不会为s2开辟空间了,所以说“s1 == s2"的输出结果为true。
所以通过这个案例也能很好的理解”==“比的是两个对象的内存地址。
分析:
“String s1 = "程序猿你好!!!";”在上面也说过了,jvm会在常量池中开辟一块空间来存放s1。
那我们主要来分析”String s3 = new String("程序猿你好!!!");“,在此之前必须要了解JVM内存区域”栈“和”堆“。
JVM内存区域相关网址:
”String s3 = new String("程序猿你好!!!");“会在”栈“中开辟一块空间来放s3,在”堆“中开辟一块空间来放new出来的对象”程序猿你好!!!“。而”==“比较的内存地址,所以很明显”s1 == s3“的结果为false。
equlas源码:
- public boolean equals(Object anObject) {
- if (this == anObject) {
- return true;
- }
- if (anObject instanceof String) {
- String anotherString = (String)anObject;
- int n = value.length;
- if (n == anotherString.value.length) {
- char v1[] = value;
- char v2[] = anotherString.value;
- int i = 0;
- while (n-- != 0) {
- if (v1[i] != v2[i])
- return false;
- i++;
- }
- return true;
- }
- }
- return false;
- }
先来分析”this == anObject“:
this指的就是”s1.equals(s3)“中的s1,anObject指的是s3,前面也说了”==“指的是内存地址,所以“s1.equals(s2)”返回的肯定也是true,这里感兴趣的自己可以去试一下。
再来分析”anObject instanceof String“:
instanceof是用来判断s3是否为String,可以看出equals比较的都是String字符串。
再看里面的内容,它先会使用”n == anotherString.value.length“来判断两个字符串的长度是否相同,再看下面的”value“和”while“这两个关键字,相信有点基础的小伙伴就可以凭借这两个关键字看出这是通过while循环比较这两个相同长度的字符的value值是否相同,由此可见,equals的主要作用就是比较两个String字符串的长度和值是否相同。
而s1.equals(s3)中,s1(程序猿你好!!!)和s3(程序猿你好!!!)的长度和值都是相同的,所以输出结果是true。