public class Person {
public int age;
public String name;
public static int flag;
public void m1() {
System.out.println("m1正常");
}
public static void m2() {
System.out.println("m2正常");
}
@Override
public String toString() {
return "Person [age=" + age + ", name=" + name + " flag = "+flag+"]";
}
public class Test {
public static void main(String[] args) {
Person x1 = new Person();
x1.age = 20;
x1.name = "张三";
x1.flag = 1;
Person x2 = new Person();
x2.age = 22;
x2.name="李四";
x2.flag = 2;
change1(x1,x2);
change2(x1,x2);
System.out.println(x1);
System.out.println(x2);
}
public static void change1(Person a,Person b) {
Person temp = a;
a=b;
b=temp;
}
public static void change2(Person a,Person b) {
int temp_age = a.age;
String temp_name = a.name;
a.age = b.age;
a.name = b.name;
b.age = temp_age;
b.name = temp_name;
}
以上代码在内存中的运行逻辑是什么样子的呢?
要想知道这个知识,我们需要先了解一下Java内存区域的分布和作用
1.方法区,方法区又分为类常量池和静态常量池
类常量池对当前的类做一个简单的概括,并未真正开辟空间
静态常量池对程序中静态的分程序、类型等进行备份
2.栈区(先进后出),方法区的方法要执行需要入栈,且栈区中可能不止一个栈
该区域用于辅助方法执行
3.堆区(只开劈非静态类型数据的空间),堆区中有一个区域叫做字符串常量池
用于辅助方法、变量等的存储
4.程序计数器
5.本地方法栈
了解这些后,我们就可以开始研究代码了
1,Person类和Test类会进入类常量池
2,其中的静态变量会拷贝一份存入静态常量池
3,main方法入栈,并在堆区开辟对应空间存储相应数据,其中字符串型存放在字符串常量池
4,执行main方法里的change1(),此时change1()方法入栈,a和b分别存储x1和x2的数值
5,执行方法后a和b的值互换,但并没有影响堆中和main方法中的数据,change1()执行完后出栈
Person temp = a;
a=b;
b=temp;
可见x1和x2没有任何变化
6,change2()方法入栈
开始执行
a.age = b.age;
a.name = b.name;
b.age = temp_age;
b.name = temp_name;
最后change2()出栈,可见堆中数据被改变了