Java基础之数据比较Integer、Short、int、short
基础很重要,基础很重要,基础很重要。重要的事情说三遍,。
今天聊一聊Java的数据比较,这个范围比较大,基础类型的比较、引用类型的比较。
前提:
1、Java和c#都提供自动装箱和自动拆箱操作,何为自动装箱,简单点说就是将值类型转换成为引用类型,自动拆箱就是将引用类型转换成为值类型。并且我们还经常被教导,要避免自动的装箱和拆箱操作,因为这个会影响性能。
2、比较常用的运算符是==,equals。
下面分几类来说明数据的比较,
引用类型之间的比较:Integer与Integer之间的比较、Boolean与Boolean之间的比较、Integer与Boolean之间的比较
值类型之间的比较:int与int之间的比较、int与bool之间的比较
值类型与引用类型之间的比较:Integer与int之间的比较、Boolean与bool之间的比较
开工
引用类型之间的比较--Integer与Integer之间的比较
简单说明一下,Integer是引用类型,代表的是整形数字
上代码
1 public static void main(String[] args) throws Exception { 2 Integer integer = new Integer(0); 3 Integer mInteger = Integer.valueOf(0); 4 Integer sInteger = 0; 5 6 System.out.println(integer == mInteger);//false 7 System.out.println(integer == sInteger);//false 8 System.out.println(mInteger == sInteger);//true 9 10 System.out.println(memoryAddress(integer)); 11 System.out.println(memoryAddress(mInteger)); 12 System.out.println(memoryAddress(sInteger)); 13 14 } 15 16 private static int memoryAddress(Object object) { 17 // 内存地址会有所不同 18 return System.identityHashCode(object); 19 }
执行结果:
分析:
1、执行结果和我们预想的不太一样,引用类型是在堆上存放的,每个引用的地址应该都不相同。但是mInteger == sInteger 执行结果为true,并且mInteger ,sInteger的内存地址是相同的。
2、要分析这个原因,我们需要了解Java设计者为了性能而进行的一些努力,查看Java源代码,可以看到Integer的valueof方法里面包含了一个缓存:其中IntegerCache.low =-127,IntegerCache.high=128
1 @HotSpotIntrinsicCandidate 2 public static Integer valueOf(int i) { 3 if (i >= IntegerCache.low && i <= IntegerCache.high) 4 return IntegerCache.cache[i + (-IntegerCache.low)]; 5 return new Integer(i); 6 }
对于使用Integer.valueof()方法,如果数值是-127至128,那么会使用缓存对象,否则会new一个对象。
3、Integer sInteger = 0; 发生了什么呢?自动装箱,等价于Integer sInteger=Integer.valueOf(0)。通过这个,我们就可以得出比较等于true的原因了,都是从缓存中读取的对象,难怪内存地址会一致。
引用类型比较--Integer与Integer引用类型比较 使用equals
上代码:
1 public static void main(String[] args) throws Exception { 2 Integer integer = new Integer(0); 3 Integer mInteger = Integer.valueOf(0); 4 Integer sInteger = 0; 5 6 System.out.println(integer == mInteger);// false 7 System.out.println(integer == sInteger);// false 8 System.out.println(mInteger == sInteger);// true 9 10 System.out.println(memoryAddress(integer)); 11 System.out.println(memoryAddress(mInteger)); 12 System.out.println(memoryAddress(sInteger)); 13 14 System.out.println(integer.equals(mInteger));//true 15 System.out.println(integer.equals(sInteger));//true 16 System.out.println(mInteger.equals(sInteger));//true 17 18 } 19 20 private static int memoryAddress(Object object) { 21 // 内存地址会有所不同 22 return System.identityHashCode(object); 23 }
分析:使用equals比较,只要数值相同,那么比较结果就是相同。查看Java源代码:
1 public boolean equals(Object obj) { 2 if (obj instanceof Integer) { 3 return value == ((Integer)obj).intValue(); 4 } 5 return false; 6 }
可以看到Integer的equals比较,其实比较的就是数值。
值类型之间的比较:int与int
上代码
1 int m=0; 2 int i=0; 3 int s=0; 4 System.out.println(m==i);//true 5 //值类型是没有equals方法 6 //System.out.println(m.equals(i));
分析:对于int 的比较,无需多言,本来就是数值比较。
Integer与int的比较:
1 Integer integer = new Integer(0); 2 Integer mInteger = Integer.valueOf(0); 3 Integer sInteger = 0;// 等价于Integer。valueof 4 int i = 0; 5 System.out.println(integer == i);//true 6 System.out.println(mInteger == i);//true 7 System.out.println(sInteger == i);//true 8 System.out.println(integer.equals(i));//true 9 System.out.println(mInteger.equals(i));//true 10 System.out.println(sInteger.equals(i));//true
分析:
1、Integer类型与int类型通过==比较,Integer会自动拆箱,转换成int数值进行比较
2、equals方法更是读取对应的int数值进行比较。
因此引用类型与值类型之间的比较,使用equals与==都可以。
简单总结:
1、引用类型之间的比较,由于存在-127至128之间的缓存对象,因此使用== 进行比较存在风险。优先使用equals进行比较
2、引用类型与值类型进行比较,由于会自动拆箱,因此使用==和equals都可以正确得到结果
3、建议在实际编码过程中,对数值的比较使用equals
深入总结:
不仅仅Integer,其他的基本类型也都存在缓存,下面给出一个简单图表进行说明
基本类型 | 装箱类型 | 取值范围 | 是否缓存 | 缓存范围 |
byte | Byte | -128~127 | 是 | -128~127 |
short | Short | -2^15 ~ (2^15 - 1) | 是 | -128~127 |
int | Integer | -2^31 ~ (2^31 - 1) | 是 | -128~127 |
|
Long | -2^63 ~ (2^63 - 1) | 是 | -128~127 |
float | Float | -- | 否 | |
double | Double |
|
否 | |
boolean | Boolean | true、false | 是 | true、false |
char | Character | \u0000 ~ \uffff | 是 | \u0000 ~ \uffff |
Java博大精深,要想深入,基础必须要好,才能避免bug。
我们程序员的职责就是少写bug,这才是我们一直学习的动力。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库