变量:值可以被改变的数据。
常量:值不能被改变的数据。
变量名必须是以字母开头,由字母或数字组成的序列。不推荐特殊的字符作变量名,如:$、Unicode 字符等。另外不能用 Java 中的保留字作变量名(编译时会报错)。
变量声明后不能参与计算,必须用赋值语句对变量进行初始化。所以一般声明变量的同时进行赋值。
一、变量
声明方式: 类型 变量名;
java 是一种面向对象语言,所有的操作都是在对象中完成,而对象又是通过类生成的。根据变量在类中的声明位置,可以把变量分为 3 类:
类变量: 声明在类方法外的变量,用 static 修饰,也称类的静态变量。在内存中只有一个副本,可以被所有该类生成的对象访问。
成员变量: 声明在类方法之外的变量,没有 static 修饰。可以不设置初始值,有默认值。
局部变量 : 声明在类方法内的变量,必须初始化,否则编译报错。
如:
public class Test { // 类变量 static int num = 1; // 成员变量 String str; public static void main(String[] args) { // 局部变量 // 整形变量 short s = 32767; // 声明一个短整型,并赋值为 32767 int i = -2147483648; long l = 9223372036854775807L; byte b = -128; // 浮点型变量 float f = 3.14F; double d = 3.1415D; // 字符型变量 char c = 'a'; // 字符必须用单引号包裹 // 布尔型变量 boolean bl = true; // 数组 int[] arr1 = new int[]{1, 2, 3}; // 定义一个存放整形数据的数组 int[] arr2 = {1, 2, 3}; // 简写方式 String[] arr3 = new String[2]; // 定义一个字符串数组,大小为 2 只能存放两个数据。 arr3[0] = "aa"; arr3[1] = "bb"; // 对象引用 Person p = new Person(20); // 对象变量是类通过 new 语句产生的 } }
二、常量
声明方式: final 类型 常量名;
关键字 final 标识这个变量只能被赋值一次,一旦被赋值就不能更改。习惯上常量名使用全大写。
public class Test { /** * 定义一个浮点型常量 * 在类中定义的常量,可以在整个类中使用 */ public static final float MATH_PIE = 3.14F; public static void main(String[] args) { // 在方法内部定义的常量,只能在方法中使用 final String A = "aaaa"; System.out.println(MATH_PIE); System.out.println(A); } }
三、内存分配
Java 程序都是运行在 JVM (Java Virtual Machine)上。JVM 启动后会向系统申请一定大小的内存。申请的内存并不是实际的物理内存大小,而是操作系统根据程序运行的情况动态分配物理内存。
Java 虚拟机 管理的内存区域叫做运行时数据区(Run Time Data Area),JVM 并将运行时数据区划分成几个专用区域,分别存储不同的信息或数据。
Runtime Data Area 的组成部分:
1. Method Area (方法区): 存储程序编译后类信息、常量、静态变量和指令字节码等。常量和静态变量在编译时就已确定,并保持在方法区中。所以通常说的 Runtime Constant Pool (运行时常量池) 也是存储在方法区。数据被所有线程共享。
2. Heap (堆): JVM 管理的最大存储区块,用于存放对象数据。垃圾回收也是针对堆中的数据进行。数据被所有线程共享。
3. JVM Stack (Java 虚拟机栈): Java 方法执行的存储模块,每执行一个 Java 方法对应则创建一个栈帧,方法的调用和执行就是入栈出栈的过程。方法中定义的变量,在方法出栈时即被销毁,所以方法中定义的都是局部变量。数据为线程独享。
4. Native Method Stack (本地方法栈): 非 Java 方法的调用接口存放区。Java 有时需要调用非 Java 的接口,如一些底层 C 接口。而本地方法就是 Java 封装的调用的其他语言方法的接口。执行方式如下图。数据为线程独享。
5. Program Counter Register ( 程序计数器 ): 用于保存下一条指令的地址。每个线程启动时都会创建自己独立的程序计数器。数据为线程独享。
其中左边绿色块数据为所有线程共享,右边白色块为线程独享。
一个 Java 程序启动时,通过 Class Loader 类装载器进入方法区,类中定义的常量,静态变量也存储在方法区中。程序执行时创建的对象数据保存在堆中,而对象调用方法时,会创建对应的栈帧在 JVM 栈中入栈出栈。
声明变量时并没有赋值,只是在内存中开辟了一个存储区块,所以并不能真正参与计算,只有赋值后才能对变量进行相关操作计算。声明变量都是在方法中进行,所以变量数据都存储在 JVM 栈中。从方法的执行过程中可以看出,变量的作用域仅在方法内部。如图:
JVM 的内存管理,这里只简略描述了下,内部的实现还有更多细致复杂的地方,已超出本节范围了。