最近刚刚读了深入理解java虚拟机一书,对于java方法是值传递还是引用传递有了自己的一些见解。
结论就是:java调用方法是值传递,注意:这个值就是变量的引用地址的值;为什么说是引用地址呢,因为虚拟机可能是通过直接引用内存地址,也可能是建立了一个句柄池。深入理解java虚拟机这本书我刚读了一遍,读后只有一种感觉,后悔为什么写了三年java代码才读这本书,之前只能算门外汉,读了这本书之后才有了真正入门的感觉。真正完全理解这本书读一遍肯定是不够的。
package ThreadDemo;
public class User {
private int money;
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public static void main(String[] args) {
User user=new User();
user.setMoney(100);
User user2=new User();
user2.setMoney(200);
swap(user, user2);
System.out.println(user.getMoney());
System.out.println(user2.getMoney());
String name="aa";
change(name);
System.out.println(name);
int i=10;
changeInt(i);
System.out.println(i);
//为什么 user和user2的已经在方法体里明明互换了引用,却没生效呢
//java值传递:调用时会先去方法区拿字节码,class文件也就是字节码文件在类加载阶段会被读到这块儿内存中。执行时虚拟机会把字节码转为基于栈的指令集, 虚拟机就会告诉电脑主机在线程内存栈创建一个帧栈,然后执行指令
//值传递 无论是对象还是基本变量 最终 他们都是将引用地址的值赋给了帧栈中方法参数对应的新的变量(相当于副本),在创建的帧栈中这个变量有自己的生命周期,随着出栈而消亡;
//所以无论副本怎么改变引用,都不会引起原方法中的变量引用 这也就解释了 为什么int和String 不改变,以及对象交换引用失效
//但是对于堆中的对象,由于原方法的变量引用和副本的引用都是指向的堆中同一个对象,所以,虽然副本不会改变原变量的引用,但是它可以改变堆中的对象
}
private static void change(String name2) {
name2="dd";
}
private static void changeInt(int i) {
i=0;
}
/**
* 将user和user2的引用互换
* @param user
* @param user2
*/
public static void swap(User user,User user2) {
User temp;//交换变量
temp=user;
user=user2;
user2=temp;
}
}
运行结果:
100
200
aa
10