==比较是对象的引用

Java代码如下,很简单.

package com.test.add;

public class TestInteger {

/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Integer int1 = 30;
Integer int2 = 30;
Integer int3 = 0;
System.out.println(int1 == int2);
System.out.println(int1 == int2 + int3);
}

}


返回的是什么,为什么。

解析如下:主要进行了自动装包,valueOf.[1种]
自动解包 intValue()[2种]
public static void main(java.lang.String[] args);
0 bipush 30 [将单字节的常量值(-128~127)推送至栈顶]
2 invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [16][调用valueOf方法]
5 astore_1 [int1][ 将栈顶引用型数值存入指定本地变量]
6 bipush 30
8 invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [16]
11 astore_2 [int2]
12 iconst_0[将int型0推送至栈顶]
13 invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [16]
16 astore_3 [int3]
17 getstatic java.lang.System.out : java.io.PrintStream [22]
20 aload_1 [int1][ 将指定的引用类型本地变量推送至栈顶]
21 aload_2 [int2]
22 if_acmpne 29[比较栈顶两引用型数值,当结果不相等时跳转]
25 iconst_1[将int型1推送至栈顶]
26 goto 30[无条件跳转]
29 iconst_0[将int型0推送至栈顶]
30 invokevirtual java.io.PrintStream.println(boolean) : void [28]
33 getstatic java.lang.System.out : java.io.PrintStream [22]
36 aload_1 [int1]
37 invokevirtual java.lang.Integer.intValue() : int [34] [调用intValue方法]
40 aload_2 [int2]
41 invokevirtual java.lang.Integer.intValue() : int [34]
44 aload_3 [int3]
45 invokevirtual java.lang.Integer.intValue() : int [34]
48 iadd[将栈顶两int型数值相加并将结果压入栈顶]
49 if_icmpne 56[比较栈顶两引用型数值,当结果不相等时跳转]
52 iconst_1
53 goto 57
56 iconst_0
57 invokevirtual java.io.PrintStream.println(boolean) : void [28]
60 return
}


另一种方式如下.

package com.test.add;

public class TestInteger2 {

/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Integer int4 = new Integer(30);
Integer int5 = new Integer(30);
Integer int6 = new Integer(0);
System.out.println(int4 == int5);
System.out.println(int4 == int5 + int6);
}
}




public static void main(java.lang.String[] args);
0 new java.lang.Integer [16][创建一个新的对象并分配内存,堆]
3 dup[复制栈顶数值并将复制值压入栈顶,栈]
4 bipush 30 [将单字节的常量值(-128~127)推送至栈顶]
6 invokespecial java.lang.Integer(int) [18]
9 astore_1 [int4] [ 将栈顶引用型数值存入指定本地变量]
10 new java.lang.Integer [16]
13 dup
14 bipush 30
16 invokespecial java.lang.Integer(int) [18]
19 astore_2 [int5]
20 new java.lang.Integer [16]
23 dup
24 iconst_0
25 invokespecial java.lang.Integer(int) [18]
28 astore_3 [int6]
29 getstatic java.lang.System.out : java.io.PrintStream [21]
32 aload_1 [int4]
33 aload_2 [int5]
34 if_acmpne 41[两个新的内存地址进行比较]
37 iconst_1
38 goto 42
41 iconst_0
42 invokevirtual java.io.PrintStream.println(boolean) : void [27]
45 getstatic java.lang.System.out : java.io.PrintStream [21]
48 aload_1 [int4]
49 invokevirtual java.lang.Integer.intValue() : int [33]
52 aload_2 [int5]
53 invokevirtual java.lang.Integer.intValue() : int [33]
56 aload_3 [int6]
57 invokevirtual java.lang.Integer.intValue() : int [33]
60 iadd
61 if_icmpne 68[比较的是intValue值]
64 iconst_1
65 goto 69
68 iconst_0
69 invokevirtual java.io.PrintStream.println(boolean) : void [27]
72 return

解析java代码为class文件,再执行JVM指令执行程序。看这个比较容易理解JVM的处理规则,其实也能更深刻的理解对象引用和值引用.
第二种情况,最后Integer先执行操作运行,这个操作会把Integer转化为int,然后再执行计算,最后再执行==操作,因为全转化为常量了,所以相等了。

JVM运行时数据区的内存模型由五部分组成
  (1)方法区
  (2)堆
  (3)JAVA栈
  (4)PC寄存器
  (5)本地方法栈
对于String s = "haha" ,它的虚拟机指令
  0: ldc "16; //String haha 2: astore_1 3: return


JVM常量池
  虚拟机必须为每个被装载的类型维护一个常量池。常量池就是该类型所用到常量的一个有序集和,包括直接常量(string,integer和floating point常量)和对其他类型,字段和方法的符号引用。对于String常量,它的值是在常量池中的。而JVM常量池在内存当中是以表的形式存在的,对于String类型,有一张固定长度的CONSTANT_String_info表用来存储文字字符串值,注意:该表只存储文字字符串值,不存储符号引用。说到这里,对JVM常量池中的字符串值的存储位置应该有一个比较明了的理解了。
  在介绍完JVM常量池的概念后,接着谈开始提到的"haha"的值的内存分布的位置。对于haha的值,实际上是在class文件被JVM装载到内存当中并被引擎在解析ldc指令并执行ldc指令之前,JVM就已经为haha这个字符串在常量池的CONSTANT_String_info表中分配了空间来存储haha这个值。
  既然haha这个字符串常量存储在常量池中,常量池是属于类型信息的一部分,类型信息也就是每一个被的类型,这个类型反映到JVM内存模型中是对应存在于JVM内存模型的方法区中,也就是这个类型信息中的JVM常量池概念是存在于在方法区中,而方法区是在JVM内存模型中的堆中由JVM来分配的。所以,haha的值是应该是存在堆空间中的。而对于String s = new String("haha") ,它的JVM指令

 new指令过程:
  要执行new指令,Jvm通过计算(indextype1<<8)|indextype2生成一个指向常量池的无符号16位索引。然后JVM根据计算出的索引查找JVM常量池入口。该索引所指向的常量池入口必须为CONSTANT_Class_info。如果该入口尚不存在,那么JVM将解析这个常量池入口,该入口类型必须是类。JVM从堆中为新对象映像分配足够大的空间,并将对象的实例变量设为默认值。最后JVM将指向新对象的引用objectref压入操作数栈。
dup指令过程:
  要执行dup指令,JVM复制了操作数栈顶部一个字长的内容,然后再将复制内容压入栈。本指令能够从操作数栈顶部复制任何单位字长的值。但绝对不要使用它来复制操作数栈顶部任何两个字长(long型或double型)中的一个字长。上面例中,即复制引用objectref,这时在操作数栈存在2个引用。
ldc指令过程:
  要执行ldc指令,JVM首先查找index所指定的常量池入口,在index指向的JVM常量池入口,JVM将会查找CONSTANT_Integer_info,CONSTANT_Float_info和CONSTANT_String_info入口。如果还没有这些入口,JVM会解析它们。而对于上面的haha,JVM会找到CONSTANT_String_info入口,将把指向被拘留String对象(由解析该入口的进程产生)的引用压入操作数栈。
Invokespecial指令
invokespecial指令过程:对于该类而言,该指令是用来进行实例初始化方法的调用。上面例子中,即通过其中一个引用调用String类的构造器,初始化对象实例,让另一个相同的引用指向这个被初始化的对象实例,然后前一个引用弹出操作数栈。
astore_1指令过程:
  要执行astore_1指令,JVM从操作数栈顶部弹出一个引用类型或者returnAddress类型值,然后将该值存入由索引1指定的局部变量中,即将引用类型或者returnAddress类型值存入局部变量1。
return 指令的过程:
  从方法中返回,返回值为void,要执行astore_1指令,JVM从操作数栈顶部弹出一个引用类型或者returnAddress类型值,然后将该值存入由索引1指定的局部变量中,即将引用类型或者returnAddress类型值存入局部变量1。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值