javaInteger等号判断怎么使用
这篇文章主要讲解了“java Integer等号判断怎么使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“java Integer等号判断怎么使用”吧!
成都创新互联主要从事成都网站设计、网站制作、网页设计、企业做网站、公司建网站等业务。立足成都服务陇西,十余年网站建设经验,价格优惠、服务专业,欢迎来电咨询建站服务:18982081108
面试题
先来看一道常见的面试题,对照上面的结论,看看能够答对几项。下面代码中打印结果为true的有几项?
@Test public void test2() { Integer i1 = 64; int i2 = 64; Integer i3 = Integer.valueOf(64); Integer i4 = new Integer(64); Integer i5 = 256; Integer i6 = Integer.valueOf(256); System.out.println("A:" + (i1 == i2)); System.out.println("B:" + (i1 == i3)); System.out.println("C:" + (i3 == i4)); System.out.println("D:" + (i2 == i4)); System.out.println("E:" + (i3.equals(i4))); System.out.println("F:" + (i5 == i6)); }
执行上面的程序,打印结果为:
A:true B:true C:false D:true E:true F:false
只有C和F项打印为false。你是否疑惑为什么i1等于i2,i1等于i3,i2等于i4,都为true,那么根据等号的传递性,i3应该等于i4啊?
为什么i1和i3相等,但i5和i6却不相等呢?
先保留疑问。下面,我们从int及Integer在JVM中的存储结构来进行分析。掌握了底层存储结构,你会发现无论题面如何变化,都万变不离其宗。
变量在JVM中的存储
在彻底弄清楚上问题之前,我们先来了解一下基础类型变量、引用类型变量在JVM中的存储。
通常变量分为局部变量和全局(成员)变量。局部变量是声明在方法内的变量;全局变量是声明在类中的成员变量。
基础类型的变量和值在分配的时候是在一起的,都在方法区或栈内存或堆内存。而引用类型的变量和值不一定在一起。
局部变量存储在方法栈中
当方法被调用时,Java虚拟机都同步创建一个栈帧,局部变量便存储在其中。当方法结束虚拟机会释放方法栈,其中声明的变量随着栈帧的销毁而结束。因此,局部变量只能在方法中有效。
此过程中,基础类型和引用类型的存储有所区别:
(1)基本类型:变量和对应的值存放在JAVA虚拟机的栈中;
(2)引用类型:变量存储在栈中,是一个内存地址,该地址值指向堆中的对象。
栈属于线程私有的空间,局部变量的生命周期和作用域一般都很短,为了提高gc效率,所以没必要放在堆里面。
全局变量存储在堆中
全局变量存放在堆中,不会随着方法结束而销毁。同样在类中声明的变量也是分为基本类型和引用类型。
(1)基本类型:变量名和值存放在堆内存中。
(2)引用类型:变量是一个引用地址,该地址指向所引用的对象。此时,变量和对象都在堆中。
举个简单的例子,如下代码:
public class Person { int age = 10; String name = "Tom"; }
对应的age和name的存储结构如下图:
结合上面的理论,我们通过一段代码来分析一下各种类型所存储的位置。
public class DemoTest { int y; // 变量和值均在堆上 public static void main(String[] args) { int x = 1; // 变量和值分配在栈上 String name = new String("cat"); // 数据在堆上,name变量的指针在栈上 String address = "北京"; // 数据在常量池,属于堆空间,指针在栈上 Integer price = 4; // 包装类型为引用类型,编译时会自动装拆箱,数据在堆上,指针在栈 } }
基础类型的栈内存储
通过上面的实例,基本了解了不同类型的值的内存分配情况。下面我们重点讨论局部变量。
下面先来看看在同一栈帧中,针对int类型的处理模式。
int a = 3; int b = 3;
上述代码中a和b均为局部变量。假设编译器先处理int a=3,此时会在栈中创建a的引用变量,然后查找栈中是否存在3这个值,如果没有就将3存放进来,然后将a指向3。
接着处理int b=3,创建完b的引用变量后,同样进行查找。因为在栈中已经有3这个值,便将b直接指向3。
此时,a与b同时指向3这个值,自然是相等的。
关于基础类型与引用类型的底层比较,可稍微延伸一下:对于“==”操作符号,JVM会根据其两边相互比较的操作数的类型,在编译时生成不同的指令:
(1)对于boolean,byte、short、int、long这种整形操作数会生成if_icmpne指令。该指令用于比较整形数值是否相等。
(2)如果操作数是对象的话,编译器则会生成if_acmpne指令,与if_icmpne相比将i(int)改成了a(object reference)。
回归正题
学习了上面的底层理论知识,我们基本上可以得出如下结论:(1)两个int类型比较,直接使用双等号即可;(2)int的包装类Integer对象比较时,使用equals进行比较即可。
但上面的结果只能说E项目是正确的。其比较项还涉及到整形的装箱拆箱操作、Integer的缓存。我们下面逐一分析。
不同创建形式的比较
先看Integer的初始化,根据Integer的内部实现,创建Integer有三种,分别是:
Integer a = new Integer(1); //创建新的类 Integer b = Integer.valueOf(2); Integer c = 3; //自动包装,会调用valueOf方法
其中直接赋值底层会调用valueOf方法进行操作的,因此这两种操作效果是一样的。
因为通过new和valueOf创建的是完全两个对象,那么针对题目中的C项,直接比较两个对象的引用肯定是不相等的,因此结果为false。但B项为什么为true呢?后面我们会讲到。
比较中的拆箱
在题目中,我们发现A、D都为true,而且它们的比较格式都是基础类型与包装类型的对比。
针对这种形式的对比,包装类型会进行自动拆箱,变成基础类型(int)。很显然,结果是相等的。
Integer的缓存
为什么i1和i3相等,但i5和i6却不相等呢?对应题目中的B和G项。这里就涉及到Integer的缓存机制。
我们上面已经知道,Integer直接赋值和valueOf是等效的,那先看一下valueOf及相关的方法。
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } 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() {} }
valueOf方法判断数字是否大于low(-128)并且小于high(127),如果满足条件,则直接从IntegerCache中返回对应数字。
IntegerCache用于存储一些常用的数,防止重复创建,在Integer类装入内存时通过静态代码进行初始化。
所以只要是用valueOf或者Integer直接赋值的方式创建的对象,其值小于127且大于-128的,无论对其进行==比较还是equals 比较,都是true。
上面的源码及原理也解释了阿里Java开发手册中所说明的原因。
为什么equals可以规避问题
对于不满足-128到127范围的数,无论通过什么方式创建,都会创建一个新的对象,只能通过equals进行比较。接下来我们再看看equals方法。
public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }
equals实现比较简单,先比较类型是否一致,如果不一致,直接返回false;否则,再比较两者的值,相同则返回true。
感谢各位的阅读,以上就是“java Integer等号判断怎么使用”的内容了,经过本文的学习后,相信大家对java Integer等号判断怎么使用这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是创新互联,小编将为大家推送更多相关知识点的文章,欢迎关注!
当前题目:javaInteger等号判断怎么使用
文章位置:http://ybzwz.com/article/gsgosh.html