类变量、成员变量、局部变量存放位置比较
三种变量易混淆,在学JVM的过程中分不清它们的存放位置,特此梳理比较。
一、实例变量
也叫成员变量、全局变量。
- 定义在类中、方法外
- 可以被 public,private,final 等修饰符所修饰
- 有默认初始值。
- 通过对象的引用来访问实例变量。
- 随着对象的建立而建立,随着对象的消失而消失,存在于对象所在的堆内存中。
二、类变量
也叫静态变量。
- 定义在类中、方法外
- 有关键字 static 修饰
- 有默认初始值。
- 可以通过对象调用,也可以通过类名调用。
- 生命周期与类共存亡。
- 对象的引用存放在方法区,如果用关键字 new 为引用类型的静态变量分配对象,该对象在堆中的地址也会存放在方法区!但是对象本身仍在堆内存中。
三、局部变量
- 定义在方法中,或者方法的形参
- 可以被final 修饰,但不可以被static 修饰
- 没有初始化值。
- 生命周期与方法共存亡。
- 存放在栈中。局部的对象的引用所指对象在堆中的地址在存储在了栈中。
举例: public class StaticObjTest {
static class Test {
static ObjectHolder staticObj = new ObjectHolder();//静态变量、类变量
ObjectHolder instanceObj = new ObjectHolder();//实例变量、成员变量
void foo() {
ObjectHolder localObj = new ObjectHolder();//局部变量
System.out.println("done");
}
}
}
- 静态变量staticObj 随着Test的类型信息存放在方法区
- 成员变量instance0bj 随着Test的对象实例存放在Java堆
- 局部变量localobj则是存放在foo() 方法栈帧的局部变量表中。
- 三个对象的数据在内存中的地址都落在Eden区范围内,所以结论:只要是对象实例 即new() 必然会在Java堆中分配。
再举个例子: public class PersonDemo
{
public static void main(String[] args)
{ //局部变量p和形参args都在main方法的栈帧中
//new Person()对象在堆中分配空间
Person p = new Person();
//sum在栈中,new int[10]在堆中分配空间
int[] sum = new int[10];
}
}
class Person
{ //实例变量name和age在堆(Heap)中分配空间
private String name;
private int age;
//类变量(引用类型)name1和"cn"都在方法区(Method Area)
private static String name1 = "cn";
//类变量(引用类型)name2在方法区(Method Area)
//new String("cn")对象在堆(Heap)中分配空间
private static String name2 = new String("cn");
//num在堆中,new int[10]也在堆中
private int[] num = new int[10];
Person(String name,int age)
{
//this及形参name、age在构造方法被调用时
//会在构造方法的栈帧中开辟空间
this.name = name;
this.age = age;
}
//setName()方法在方法区中
public void setName(String name)
{
this.name = name;
}
//speak()方法在方法区中
public void speak()
{
System.out.println(this.name+"..."+this.age);
}
//showCountry()方法在方法区中
public static void showCountry()
{
System.out.println("country="+country);
}
}
在上面代码中更容易看出区别,这部分还是要多想多记!