概述
目录
前言
一、考点
二、分析
1、局部变量与成员变量的区别
2、代码分析
后记
前言
- 首先,咱们来看一道面试题,题目如下,求打印结果
public class Test {
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){
Test T1 = new Test();
Test T2 = new Test();
T1.test(10);
T1.test(20);
T2.test(30);
System.out.println(T1.i + "," + T1.j + "," + T1.s);
System.out.println(T2.i + "," + T2.j + "," + T2.s);
}
}
- 答案如下:
2,1,5
1,1,5
如果是一眼就看破答案的大佬,大可出门右转,小弟就不耽误大佬的时间了,接下来就深入研究此题
一、考点
- 就近原则
- 变量分类
- 成员变量:类变量、实例变量
- 局部变量
- 非静态代码块的执行:每次创建实例对象都会执行
- 方法的调用规则:调用一次执行一次
二、分析
1、局部变量与成员变量的区别
【1】声明的位置
- 局部变量:方法体{}中,形参,代码块{}中
- 成员变量:类中方法外
- 类变量:有 static 修饰
- 实例变量:没有 static 修饰
在本题目中,局部变量有:
- 第 6 行非静态代码块的局部变量 i
- 第 11 行形参局部变量 j
- 第 16 行形参局部变量 args
- 第17/18行局部变量 T1,T2
成员变量有:
- 第 2 行的类成员变量 s
- 第 3,4 行的实例成员变量 i,j
【2】修饰符
- 局部变量:final
- 成员变量:public、protected、private、final、static、volatile、transient
【3】存储位置
- 局部变量:栈
- 实例变量:堆
- 类变量:方法区
【4】作用域
- 局部变量:从声明处开始,到所属的 “}” 结束
- 实例变量:在当前类中“this.”访问,在其他类中“对象名.”访问
- 类变量:在当前类中“类名.”访问,在其他类中“类名.”访问
这里注意:在本题中,第 7 行如果是 this.i++,那么就是实例成员变量自增,i++ 则表示的是 i = 1 的自增(就近原则)
【5】生命周期
- 局部变量:每一个线程每次调用执行都是新的生命周期
- 实例变量:随着对象的创建而初始化,随着对象的被回收而消亡,每一个对象的实例变量都是独立的
- 类变量:随着类的初始化而初始化,随着类的卸载而消亡,该类的所有对象的类变量都是共享的
2、代码分析
咱们一行行的来执行分析,看看在内存中是如何运行的,首先从 main 开始,在栈中给 main 方法分配了一块空间,进入第一行:
【1】Test T1 = new Test()
- Test T1:由于 T1 是局部变量,便在分配给 main 方法的栈中分配一块空间给 T1,同时在方法区开辟了一块空间存放类信息,也就是Test.class,加载静态变量 s,初始化为 0
- new Test():在堆中开辟了一块空间存放实例对象,而具体存放的是什么,就要看实例化过程中实例变量了
- 实例化:实例化的过程其实是在底层执行了 <init>() 方法,实例化方法其实是有实例变量、非静态代码块,构造器等组成的
- 实例变量存储:从实例变量可以看出,实例对象空间里面存放的是 i 和 j 两个变量,默认值为 0,也就是第 3,4 行的两个变量
- 非静态代码块的执行:也就是第 5~10 行非静态代码块的执行,会在分配给 main 方法的栈中分配一块空间给非静态代码块,里面存储了局部变量 i,初始化为 1,i++后值为 2;由于 j 是成员变量,而 j 默认值为 0,所以 j++ 后值为 2;s 由于是共享的,所以每次执行都会 +1,执行后值为 1
- 释放资源:执行完后,栈的资源便释放,非静态代码块中的 i 又变为 0(T1.j 是成员变量,不释放,值为 1;静态变量共享,不释放,值为1)
执行后:T1.i = 0,T1.j = 1,s = 1
【2】 Test T2 = new Test()
这一步和上一步执行的是一样,不同的是静态变量 s 值 +1,执行后值为 2
执行后:T2.i = 0,T2.j = 1,s = 2
【3】T1.test(10)
- T1.test():
- 在栈中开辟了一块空间存放 T1.test() 方法
- 在存放T1.test() 方法的空间里面开辟一块空间存放局部变量 j,初始值为 10
- test() 方法执行:
- j++:局部变量自增,执行后值为 11
- i++:就近原则,i 会去找成员变量,由于之前成员变量 i 默认初始化为 0,所以自增后值为 1
- s++:s 由于是共享的,所以每次执行都会 +1,执行后值为 3
- 资源释放:执行完后,栈的资源便释放,test() 方法中的 j 又变为 0,而 i 是成员变量,不释放,值为 1,静态变量共享,不释放,值为3(此时成员变量 T1.j 值为 1)
执行后:T1.i = 1,T1.j = 1,s = 3
【4】 T1.test(20)
这一步和上一步执行的是一样,执行test() 方法,局部变量 j、成员变量 i、静态变量 s 都自增加 1;释放时,局部变量 j 释放,成员变量 T1.i 自增加 1,值为 2,静态变量 s 值 +1,执行后值为 4(此时成员变量 T1.j 值为 1)
执行后:T1.i = 2,T1.j = 1,s = 4
【5】T2.test(30)
这一步和上一步执行的是一样,执行test() 方法,局部变量 j、成员变量 i、静态变量 s 都自增加 1;释放时,局部变量 j 释放,成员变量 T2.i 自增加 1,值为 1,静态变量 s 值 +1,执行后值为 5(此时成员变量 T2.j 值为 1)
执行后:T2.i = 1,T2.j = 1,s = 5
所以最后:T1.i = 2,T1.j = 1,s = 5
T2.i = 1,T2.j = 1,s = 5
后记
分析了这么多,不知道有没有真正理解呢,如果将这个题目改为如下代码,输出结果会是怎样呢?请自行分析
public class Test {
static int s;
int i;
int j;
{
int i = 1;
this.i++;
j++;
s++;
}
public void test(int j){
this.i++;
j++;
s++;
}
public static void main(String[] args){
Test T1 = new Test();
Test T2 = new Test();
T1.test(10);
T1.test(20);
T2.test(30);
System.out.println(T1.i + "," + T1.j + "," + T1.s);
System.out.println(T2.i + "," + T2.j + "," + T2.s);
}
}
最后
以上就是愤怒星月为你收集整理的从内存分析局部变量与成员变量的区别(Java)前言一、考点二、分析后记的全部内容,希望文章能够帮你解决从内存分析局部变量与成员变量的区别(Java)前言一、考点二、分析后记所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复