java中局部变量包含_Java 成员变量和局部变量

通过一个简单的 demo 我们学习下 java 中成员变量和局部变量的相关知识点。

Demo

说说下面代码执行打印的结果是什么?

public class MainClass {

public static void main(String[] args) {

// 局部变量 m1 Variable m1 = new Variable();

// 局部变量 m2 Variable m2 = new Variable();

m1.add(10);

m1.add(20);

m2.add(30);

System.out.println(m1.i + "," + m1.j + "," + m1.s);

System.out.println(m2.i + "," + m2.j + "," + m2.s);

}

}

class Variable {

// 静态成员变量,类变量 static int s;

// 成员变量,实例变量 int i;

// 成员变量,实例变量 int j;

{

// 局部变量 int i = 1;

// 就近原则,这个 i 指向的是上面这个 i i++;

j++;

s++;

}

// j 是局部变量 public void add(int j) {

// 就近原则,这个 j 指向的是局部变量 j,形参 j j++;

i++;

s++;

}

}

结论

2,1,5

1,1,5

解析

我们结合 jvm 来解析下为什么会有这样的结果,jvm 的几块区域:堆、栈、方法区。堆:存储对象

栈:方法执行栈

方法区:存储 class 文件信息

假设我们现在有一个 jvm 如下图:

我们一行一行的分析代码,代码的入口是 main 方法,

第一行代码

Variable m1 = new Variable();

main 方法开始,因为它是个方法,所以要压栈。

第一句话,创建一个 Variable对象,存储在了堆区,同时加载了Variable.class 到方法区。

我们知道类的静态成员变量是存储在常量池(方法区),所以此时 s 也划分一个区域。具体看下图:这里强调一点,jvm 不是一次性加载所有 class 到 jvm 的,是按需加载。可能你整个程序都没有用到某个 class,那么从头到尾就不会去加载它。

main 方法压栈,每个方法都有自己的栈帧,栈帧中存储局部变量

执行第一行代码,new 了一个 Variable 对象

首先将 variable 的 class 加载到方法区,划出一块区域,然后里面有一个静态成员变量存储到常量池 s 初始化值为 0。【基本数据类型初始化值为0】s 也被称为类变量。

在堆中创建一个 variable 对象区域,里面有 2 个成员变量 i = 0,j = 0,这 2 个也叫实例变量。

调用对象的构造方法去实例化一个 variable 对象,此时会执行 Variable.方法,默然 init 方法是每次构造方法都会调用一次的,init 方法执行的代码包括:非静态代码块、非静态实例变量显式赋值代码、构造器方法。

因为 init 是一个方法,所以也要压栈【init 是 jvm 指令方法】

init 方法压栈,有一个局部变量 i = 1,然后 i++,i 被修改为了 2

然后 j++,因为就近原则,找到了对象的 j,所以堆中的 j 被修改为了 1

然后 s++,找到了方法区的 s,改为 1

然后在栈中,创建局部变量 m1,存储的是堆中对象的地址。

实际第一行最后的执行结果:

我们可以在第一行后面打印下结果:

0,1,1

第二行代码

又实例化了一个 Variable 对象,大家尝试自己分析一下,自己画图,然后结果和我这里的对比看看。

第二个方法又调用了 Variable.方法,有一个压栈和出栈的过程,此时对象 m2 创建了,而且方法区的 s = 2。

图片有错误,蓝色框的应该是 m2

第三行代码

m1.add(10);

方法调用,压栈。

add 方法压栈,局部变量j = 10,然后代码中 j++,j 被修改为 11

i++,找到最近的就是对象的实例变量 i,被改为 1

s++,找到方法区的 s = 3

然后 add 方法弹出 局部变量 j 消失

后面的代码

后面大家就都应该可以自行分析了吧。

变量名重名,this 的作用

上面的非静态代码块中有一个局部变量 i,和我们的实例变量 int i 重名了,因为就近原则,导致紧跟着的 i++中的 i 使用的是局部变量 i。那么我们怎么调用实例变量呢?使用 this 关键字

// 成员变量,实例变量int i;

int j; |

{ |

int i = 1; |

this.i++; ---> //指向的是最上面的 i,如果不加 this,则指向代码块的 i j++;

s++;

}

生命周期

局部变量

跟随方法,方法入栈,变量产生,方法结束,出栈,局部变量销毁

实例变量

随着实例,实例创建,实例变量被创建初始化,实例用完被回收,变量销毁。

类变量

随着类走,jvm 启动加载了 class 后,初始化类变量,jvm 关闭了,class 信息销毁,类变量销毁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值