0. 说明
从字面上看,即便不是Java coder或者 计算机人,也大概能猜到这两个是判断是否相等的。但是是判断什么相等的,估计也就计算机人才知道吧,这个议题感觉已经是老生常谈了,为了一篇总结完善的文章,我今天早早起床,为的就是预留出时间完成这篇文章。本文主要解决的就是标题中两种“相等”判断的特点和区别。
注意一点就是`equals()`是对象的方法,所以基本数据类型不会存在这种判定相等的方式。
1. 基本概念
先不要着急,为了讲清楚本文核心问题,首先我们先了解几个Java中的概念。
1.1 基本数据类型
Java中有八种内置的基本数据类型,其中有六种数字(Number)类型, 一种是布尔(Boolean)类型,一种是字符(Char是字符,不是字符串)类型是具体如下表:
![8bfbbfbc607189e68069f931517775d1.png](https://i-blog.csdnimg.cn/blog_migrate/513d9a5c04683c019b2d9dfc017f8bf4.jpeg)
基本数据类型以及对应的封装类
1.2 引用类型
在Java中除了八种基本数据类型之外,其他的都属于对象,也就是引用类型,其意思是有一个引用指向对象在内存中存在的真实空间地址。例如Java中的String,List等对象,每一个引用对象,都会有一个引用名称和引用对象,也就对应于有一个引用名称的存储地址和引用对象的地址,如下图:
![25c36410da440081b6ebb48736fe8f89.png](https://i-blog.csdnimg.cn/blog_migrate/1c6e6207ec9db9200ac06a98846ca70e.jpeg)
引用对象在内存中的近似样子
我们平时见到的如下代码:
String str = new String();
其中str就是对象的引用名称,它指向的是这个对象真实存在的地址。(如果讲的不够清楚,欢迎补充,请勿怼)
1.3 封装类型
封装类型广义上来讲就是java中的所有对象,狭义上讲就是八种基本数据类型对应的一个引用类型。
综上,我们画图表示下在内存中基本数据类型的存储样子和引用类型的存储样子。
![779f35eae009c8635db7c44d6a51f7f5.png](https://i-blog.csdnimg.cn/blog_migrate/6aec612b09267e902290d0702bc2038e.jpeg)
内存中数据存储模样
上面表示内存的图形的代码如下:
int a = 12;Integer b = 12;Integer c = new Integer(12);String str1 = "Love";String Str2 = new String("Love");
先说`int a = 12`,对于基本数据类型,可以将其真实的值保存在栈空间中;
对于`Integer b = 12`,这是分装对象,所以存在引用,将引用存在栈空间,同时指向常量池中的真实值;
对于`Integer c = new Integer(12)`, 这就是完全面向对象了,首先是引用存在栈空间中,对象存在堆空间中,引用指向堆空间中真实的对象,而对象的值指向真实的值;
对于`String str1 = "Love"`, 和`Integer b = 12`是类似的;
对于`String str2 = new String("Love")`,和`Integer c = new Integer(12)`类似。
2. 示例
下面举几个代码例子,看下真实的结果。
2.1 基本数据类型
基本数据类型之间相互判定是否相等比较简单,直接是字面量
@Testpublic void base_type_equals() { int a = 12; int b = 12; System.out.println(a == b);}
运行结果:
true
2.2 基本数据类型和封装类型
基本类型没有equals方法。
@Testpublic void base_and_package_type_equals() { int a = 11112; Integer b = 11112; Integer c = new Integer(11112); System.out.println(a == b); System.out.println(b.equals(a)); System.out.println(a == c);}
运行结果:
truetruetrue
2.3 封装类型和封装类型
这个就神奇了,睁大眼睛。
@Testpublic void package_and_package_type_equals() { Integer a = 120; Integer b = new Integer(120); System.out.println(a == b); System.out.println(a.equals(b)); Integer c = 11112; Integer d = new Integer(11112); System.out.println(c == d); System.out.println(c.equals(d)); Integer e = 120; Integer f = 11112; System.out.println(a == e); System.out.println(a.equals(e)); System.out.println(c == f); System.out.println(c.equals(f));}
运行结果:
falsetruefalsetruetruetruefalsetrue
神奇的地方在于最后四个输出。为什么a和e是相等,而c和f却不相等。我们先来看下Integer的源码:
...public final class Integer extends Number implements Comparable {... private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} }...}
源码中可以看到在-128~127之间的整数是相等的,而这个范围外的就不行了。这里面的道理深层次的就涉及到JVM内存模型的内容了,首先是Integer这个类会被加载到内存中,也就是说Integer内的常量也在内存中了,而上面的直接`Integer var = 120`都是指向这个地址的。所以==是true。
2.4 字符串类型
字符串类型,就是直接常量还是对象的区别。
@Testpublic void string_equals() { String str1 = "Love"; String str2 = "Love"; String str3 = new String("Love"); String str4 = new String("Love"); System.out.println(str1 == str2); System.out.println(str1 == str3); System.out.println(str3 == str4); System.out.println(str1.equals(str2)); System.out.println(str2.equals(str3)); System.out.println(str3.equals(str4));}
运行结果:
truefalsefalsetruetruetrue
第一个相等的原因是str1和str2都指向的是常量池中的"Love"对象。
希望本文对你有在理解Java比较的时候有所帮助。
限于笔者知识有限,如果不足之处请帮忙指正,不喜勿喷