变量是内存中开辟的一块存储区域,用于记录和存储不断变化的数据的值。
变量有固定的定义格式,当我们在进行运算和操作时,发现有部分数据会不断发生变化,而我们又需要重复操作这部分数据时,就可以定义一个变量将其进行记录。
常量也是一块存储区域,在定义常量时会进行一次赋值,之后一直到常量的生命周期结束,该常量的值都不会被改变及被第二次赋值。
1.类变量(静态变量)
类变量是指被static关键字修饰的变量,静态变量属于类,不属于某个实例对象,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配内存,静态变量就可以使用了。因此,静态变量可以直接使用类名来引用。
java虚拟机在加载类的过程中未静态变量分配内存,静态变量位于方法区,能够被类的所有实例共享。
静态变量的生命周期取决于类的生命周期,当类被加载进JVM的时候,静态变量被创建并分配内存空间,当类被卸载时(JVM停止),静态变量被摧毁,并释放所占用的内存。
2 实例变量
实例变量是指没有被static修饰的变量。
实例变量属于某个对象的属性,必须创建了实例对象,其中的实力比爱你量才会被分配空间,才能使用这个实例变量。
类的每一个实例都有对象的实例变量,每创建一个类的实例,java虚拟机为实例变量分配一次内存,实例变量位于堆区中。
当创建所在类的对象的时候,实例变量被创建并分配内存空间,当该对象被GC回收时,实例变量生命周期结束。
3 局部变量
存在位置:方法形参,代码块中,方法内
局部变量的生命周期开始于当代码执行到初始化变量的时候,当所在的方法/代码块结束的时候,生命周期结束,将局部变量位于当前方法的栈帧中。
4.字符串常量
字符串char s="hello"; 与char s[]="hello";,看似都是将hello字符串的地址赋值给指针p。
但是前面一个表达式是字符串常量的地址赋值给指针,该指针指向的字符串中的字符是不允许被更改的。
而后面一个表达式是将该字符串的每一个字符赋值给数组,该指针指向的数组的首地址,而数组成员是变量,因此可以允许被更改赋值。
对于字符串常量的生命周期,举例如下:
char *s0 = "hello"
s0="world"
就是说如果开始s0指针指向“hello”这个字符串这个常量的地址,但是当s0指针指向了“world”符串的时候那么“hello”这个字符串在内存中的是否会被释放掉,还是会一直存在内存中,直到程序结束。
5.JVM内存区域
5.1方法区
在java的虚拟机中有一块专门用来存放已经加载的类信息、常量、静态变量以及方法代码的内存区域,叫做方法区。
5.2常量池
常量池是方法区的一部分,主要用来存放常量和类中的符号引用等信息。
5.3堆区
堆内存的数据生命周期由调用者进行制定,除非内部数据不再被栈引用指向,否则会一直存在于堆内存空间。当内部实体不再被指向,内存空间不会立即释放,而是在不定时的时间范围内被Java自带的垃圾回收机制所回收。
数组、对象以及引用指向的实体(用于存放类的对象实例)都被存放在堆内存中。
5.4栈区
也叫java虚拟机栈,是由一个一个的栈帧组成的后进先出的栈式结构,栈桢中存放方法运行时产生的局部变量、方法出口等信息。当调用一个方法时,虚拟机栈中就会创建一个栈帧存放这些数据,当方法调用完成时,栈帧消失,如果方法中调用了其他方法,则继续在栈顶创建新的栈桢。
栈内存最大的特点是内部数据的生命周期都很短,数据在生命周期结束之后会自动释放。
主要用于存放局部变量和局部常量。
6. 类的生命周期
生命周期也称作作用域,是指常量和变量都有自己固定的生效范围,一旦在这个范围之外就会失去作用。生命周期一般以区间作为界限。 详见文章:Winston Lu:java面试题总结(一):JVM详解zhuanlan.zhihu.com