成员变量:
位置:方法外类的里面
使用范围:整个类
内存:堆
生命周期:随着类创建对象而出现,随着对象呗回收而消失
局部变量:
位置:方法内
使用范围:整个方法
内存:栈
生命周期:当方法被调用时才出现随着方法执行结束而消失
栈:
一般来说,基本数据类型直接在栈中分配空间,局部变量(在方法代码段中定义的变量)也在栈中分配空间
当局部变量所在的方法被执行完后将会立即被GC进行回收,还有一种引用数据类型,就是我们通常所说的需要new 的
对象其实也是存在于栈空间中,此时JVM在栈中分配一个地址空间–地址值,在堆空间中给该对象分配一个空间,栈空间中地址空间指向了堆空间
堆:
堆:一般用来存放用关键字new出来的数据。
代码参考如下
package demo;
public class Student {
private String name;
private int age;
public void study() {
System.out.println("I love study!");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package demo;
public class StudentDemo {
public static void main(String[] args) {
Student student = new Student();
System.out.println(student.getName() + ":" + student.getAge());
student.setName("John");
student.setAge(23);
System.out.println(student.getName() + ":" + student.getAge());
student.study();
Student student2 = student;
student2.setName("Jack");
student2.setAge(25);
System.out.println(student2.getName() + ":" + student2.getAge());
System.out.println(student.getName() + ":" + student.getAge());
}
}
当我们运行程序时,JVMS会把Student类与StudentDemo类编译完然后加载到JVM中一个叫做方法区的地方,类的成员变量与成员方法也被加载到方法区中,此时的内存模型如下
可以看到study方法右边有一个16进制的标记,而name与age变量没有,这是因为每个对象都有自己的成员变量,而类中的成员方法却可以被每个对象所共用,为了节省内存空间,JVM为方法分配了该标记(也叫内存地址)便于每个new 出来的对象查找该方法,接着JVM将会自动查找main方法,在栈中为main申请开辟一个空间(入栈)然后执行第五行代码
这时候JVM在堆空间中分配一块内存给student对象,并为其在栈中开辟一块地址空间指向堆里面的student对象区,如果Student对象成员变量没有初始化的话,系统将会默认给予初始化,此时的内存模型如下
此时执行:
程序为student对象的成员变量赋值,JVM会根据student所指向的地址向堆内存中寻找student对象的空间并找到该对象的变量,进行新值的指定。
此时执行
这时候student对象调用study方法,JVM在栈空间中为study方法申请了一块内存空间
study方法执行完后,立即释放栈空间,代码执行
student2对象引用指向了student所指的内存引用地址
执行代码:
为student2的变量赋值,由于student2和student指向了同一个地方,所以这时student的值也将改变
最后执行结束:main方法中所有代码执行完毕,main方法所用的栈空间也被回收,而堆空间等待被GC回收
代码执行如下
null:0
John:23
I love study!
Jack:25
Jack:25
**分析总结:**成员变量存在于堆中,每个对象都拥有自己的成员变量,成员方法存在方法区,被所有对象共享,并在加载到方法区后自动赋予地址值作为标记等待被对象调用。类的class文件被加载到方法区,然后在根据解析class字节码文件流,将成员变量分配到堆中,局部变量分配到栈中,引用变量提供地址空间进行指向操作,局部变量直接在栈中开辟空间(局部变量只支持基本数据类型和引用数据类型,前者直接引用,后者采用间接引用,给地址空间的形式进行指向堆内存)