局部变量和成员变量定义
局部变量和成员变量他们的定义不同,在不同的位置可能就是不同的变量,根据声明的位置不同:
局部变量
定义在方法体{}中,形参上,代码块{}中。 存放在 栈 中,方法执行完就没了。
成员变量
在类中,但是在方法外。
类变量: 有static修饰,存放在方法区中,整个类共享。
实例变量: 没有static修饰,存放在堆中,实例自己拥有。
案例
public class VariableCase {
static int s;
int i;
int j;
//非静态代码块
{
int i = 1;
i++;
j++;
s++;
}
public void test(int j){
i++;
j++;
s++;
}
public static void main(String[] args) {
VariableCase vc1 = new VariableCase();
VariableCase vc2 = new VariableCase();
vc1.test(10);
vc1.test(20);
vc2.test(30);
System.out.println(vc1.i + "," + vc1.j + "," + vc1.s); // 2 , 1 , 5
System.out.println(vc2.i + "," + vc2.j + "," + vc2.s); // 1 , 1 , 5
}
}
题解思路: 根据局部变量 和 成员变量的定义,并画出虚拟机的堆、栈、方法区等。
(1)执行第一行代码,vc1
是局部变量,存储在栈中。然后指向堆中的一new
出来的VariableCase
对象。根据上一节介绍的,在new VariableCase()
时,虚拟机会执行<init>
方法,该方法就是去执行 非静态代码块、非静态变量、构造方法这三个东西。 所以,首先i
和j
都进行初始化,他们的值都是0。还有一个类变量s
存储在方法区中,值也是0。 然后会执行非静态代码块的内容,首先,int i = 1
是定义了一个局部变量,下一行的i++
,根据就近原则,这个i
是局部变量i
,局部变量i
变为2。 然后j++
指的实例变量,s++
是类变量,执行后j = 1, s= 1
。 这行执行完,vc1
指向对象的值分别为:i = 0, j = 1, s = 1
。要注意的是,i
并没有++
,因为++
的i不是这个i
。
(2)执行第二行代码,初始化vc2
。在堆里面有另外一个对象VariableCase
,里面包含i
和j
,初始化值都是0,同时该对象还有类变量s
,在(1)的时候,这个值已经是1。 然后执行<init>
方法,执行到非静态代码块,执行后,该对象的i = 0, j = 1
,类变量s=2
。
(3)执行第三行代码,调用实例方法。在方法里面局部变量 j = 10
。 i++
,这里的i就是该对象指向的i
,而j++
中的j
根据 就近原则, 指的是这个test()
方法里面的局部变量j
,s++
还是指的类变量s
。所以,该行执行完后,vc1
指向的对象,i = 1, j = 1,
类变量 s = 3
。
(4)执行第四行代码,和第三行一样,执行完后,vc1
指向的对象,i = 2, j = 1
,类变量 s = 4
。
(5)执行第五行代码,这里是用vc2
调用,执行完后,vc2
指向的对象,i = 1, j = 1, s = 5
。
综上,对于vc1, i = 2,j = 1
。
对于vc2, i = 1,j=1
。
类变量s = 5
。
虚拟机堆栈图:
总结
最好画出类初始化,方法执行的堆栈信息。