简单介绍一下指令
- bipush 将 -128~127常量压栈
- ldc 数值常量或String常量值从常量池中压栈
- load1 将局部变量1压栈
- store1 抛出栈顶数据给局部变量1
- new 在java堆上为对象分配内存空间,并将地址压入操作数栈顶
- dup 复制操作数栈顶值,并将其压入栈顶,也就是说此时操作数栈上有连续相同的两个对象地址
- invokespecial 在这里调用 init方法 为对象初始化
第一部分
pp赋值p的时候 直接bipush 100 + istore_1 看着像将100 压栈 把100传递给 pp。但是我们发现 pp 和 p指向的是同一个地址。所以最终还是引用传递。同理后面a,b一样。这也说明一点 final static int p = 100原本应该直接创建在永生区的东西。因为本身就在常量池。所以jvm帮我们优化了。
第三部分
不管是 ldc压入字符串还是 new dup invokespecial创建obj对象地址。 c 和 d 地址一样, o 和 clone地址一样。我们可以说这里也是引用传递。
第二部分 最难理解的部分
跟操作字符串的指令差不多,可是最终导致 q,r,z三个int变量指向地址都不一样。
在加大难道看看
我们也从左边代码地址找规律,
- int 传 int 地址会发生变换
- Integer 传 Integer 地址不会发生
- int 传 Integer 地址会发生变化
- Integer 传 int 地址会发生变化
我们再从右边指令找规律
- int 传 int 时候 是 istore iload
- int 传 Integer 的时候 先调用了 Integer.valueOf()变成 Integer 再 astore aload
- Integer 传 int 的时候 先调用 Integer.intValue 变成 int 再 istore iload
猜测
astore aload 在字符串 和 Objec 传递的时候都用到,那么我们认为他是引用传递
istore iload 指定是值传递,但是一开始 传递100的时候也是用了这个指令。其结果是地址一致。
引用传递我们就不分析了,分析一下值传递。 先理解 不在常量池的 int值传递。 int a = 10000, int b = a; istore存值,iload获取值。因为获取到的是值,所以需要开辟一个新的地址空间去存取这个值。这没问题。 int c = 100, int d = c; istore存值,iload获取值。我们明确知道 jvm规定了这个指定是传值。也就是说 d理应需要开辟一个空间存取100。那为什么没有开辟。那只能认为是jvm做了优化。在开辟新区域存储这个100的时候,发现这个值在常量池就不创建的优化
总结
java从官网指令确实说明了 有值传递 和引用传递的概念,我们也看到了 值传递和引用传递的区别。 值传递可能需要开辟新空间去存储值,然而引用传递是不需要的。传递引用,让变量指向同一个地址空间。 但是仔细想想 不管是 int a,还是 string 他们其实都是指向一个地址。然后通过 类型截取对应数据解析。== 传给 int的时候虽然是个 值 但是最终会 变成 地址 , a 指向这个地址。传给 string时候,是地址,但是 地址也是一个值。本质上是个字节所以,所以对于变量来说是赋值传递,然而新的String变量又指向同一个对象,因此对于对象来说是引用传递。==所以我认为 弄明白这一点,java传递本质上是引用还是值不好说。,如果面试官问到可以battle一下您的新观点。
实验代码
public class CCN {
private final static int p = 100;
public static void main(String[] args) {
System.out.println("p====" + System.identityHashCode(p)); //P====1198108795
int a = 100;
System.out.println("a====" + System.identityHashCode(a)); //a====1198108795
int b = a;
System.out.println("b====" + System.identityHashCode(b)); //b====1198108795
System.out.println("**************************************");
int q = 100000000;
System.out.println("q====" + System.identityHashCode(q)); //q====214126413
int r = q;
int z = r;
System.out.println("r====" + System.identityHashCode(r)); //r====396873410
System.out.println("z====" + System.identityHashCode(z)); //z====1706234378
System.out.println("**************************************");
Integer qq = 100000000;
System.out.println("qq====" + System.identityHashCode(qq)); //qq====1867750575
Integer rr = qq;
Integer zz = rr;
System.out.println("rr====" + System.identityHashCode(rr)); //rr====1867750575
System.out.println("zz====" + System.identityHashCode(zz)); //zz====1867750575
System.out.println("**************************************");
int qqq = 100000000;
System.out.println("qqq====" + System.identityHashCode(qqq)); //qqq====2046562095
Integer rrr = qqq;
Integer zzz = rrr;
System.out.println("rrr====" + System.identityHashCode(rrr)); //rrr====1342443276
System.out.println("zzz====" + System.identityHashCode(zzz)); //zzz====1342443276
System.out.println("**************************************");
Integer qqqq = 100000000;
System.out.println("qqqq====" + System.identityHashCode(qqqq)); //qqqq====769287236
int rrrr = qqqq;
int zzzz = rrrr;
System.out.println("rrrr====" + System.identityHashCode(rrrr)); //rrrr====1587487668
System.out.println("zzzz====" + System.identityHashCode(zzzz)); //zzzz====1199823423
System.out.println("**************************************");
String c = "abc";
System.out.println("c====" + System.identityHashCode(c)); //c====1867750575
String d = c;
System.out.println("d====" + System.identityHashCode(d)); //d====1867750575
System.out.println("**************************************");
Object o = new Object();
System.out.println("c====" + System.identityHashCode(o)); //o====1225358173
Object clone = o;
System.out.println("clone====" + System.identityHashCode(clone)); //clone====1225358173
}
}