类变量、成员变量、局部变量存放位置比较

三种变量易混淆,在学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);
}
}

在上面代码中更容易看出区别,这部分还是要多想多记!

------ 本文结束感谢您的阅读 ------