程序的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public
class
Point{
int
x;
int
y;
public
Point(
int
x,
int
y){
this
.x=x;
this
.y=y;
}
public
static
void
main(String[] args){
int
a=
4
;
Point p1 =
new
Point(
3
,
4
);
Point p2 = p1;
p1.x =
30
;
System.out.println(p2.x);
}
}
|
堆和栈。
栈(stack):
1. 内存是连续的空间。整个stack空间大小是确定的。
2. 存放局部变量
3. 存放特点:先进后出,后进先出。
堆(heap):
1. 是不连续的空间。
2. 存放创建的对象。
代码执行步骤分析
参照下面的截图分析。
首先,这段代码被执行的时候
第一步要加载类信息,加载Point类信息;把Point类的信息放在堆里面。Point类的信息就是public class Point下的代码,main方法也要包含在内,逻辑上main方法不属于Point类,但物理上main方法是属于Point类的。(名亡实存,大概可以用这么一个词来解释)。
第二步就是运行main方法了,方法运行时放在栈帧里面。所以先将main方法放入栈帧里,按代码顺序执行。1. int a = 4; 2.Point p1=new point(3,4); 又出现了一个方法,所以此时开辟一个新的栈帧,并把这个方法进栈。(ps:此时p1的地址默认为null)。
第三步是Point方法的进栈,也即构造器的进栈。Point方法读入x=3,y=4,同时执行int x;int y; 在堆里面创建一个对象,对象的属性有两个,x和y,都默认为0;假设这个对象的地址为010203;那么this的地址也就为010203(因为this指向的地址原本就是这个对象的地址)。
第四步,接着按顺序执行的方式执行构造器,即this.x=x;this.y=y;x按照地址找到this.x并将值赋给this.x,y同样按照地址找到this.y并将值赋给this.y,上一步在堆里创建的对象的值就改变了,堆里的x变为3,堆里的y变为4。
第五步,执行完毕,将构造器出栈,此时,程序会自动的把this的地址return给p1;那么p1的地址就变成了010203;
第六步,Point p2=p1;p1.x=30;System.out.println(p2.x);顺序执行这些语句,第一句p2的地址也变为了010203,第二句p1指向的x的值变为了30;即010203中的x变为了30;第三句,打印p2中的x,按照p2的地址,找到了010203中的x为30,将之打印出来。程序执行完毕,main方法出栈。