书中,Java的基本类型,是在谈“对象无处不在”时谈到的,首先它提出:
- 通过引用操作对象
- 必须创建所有对象
这里的创建,通常指用new关键字来创建,而在堆上操作没那么高效,所以一些经常使用的类型,它们享受了特殊待遇:使用和C/C++相同的实现机制,无需new,而是直接创建一个自动变量,该变量会直接在栈上保存它的值。
Java就把这种享受特殊待遇的类型称为基本类型。包括如下几种:
- boolean
- char
- byte
- short
- int
- long
- float
- double
- void
上面提到基本类型变量会保存在栈上,书中系统回答了“数据保存在哪里”这个问题,有5种数据存储方式:
- 寄存器
- 栈
- 堆
- 常量存储
- 非RAM存储
讲常量存储时,书上有一句话我不太理解 ,它说:常量通常会直接保存在程序代码中。于是我去查了下Java内存的细节,Java程序的执行过程,总体是这样的:
其中,内存又可分为:堆、方法区、栈、程序计数器、虚拟机栈、本地方法栈。通过分析程序的执行过程可以更好的理解这些概念,极客时间(《Java性能调优实战》)上有个不错的例子,我这里搬运过来供大家参考。代码如下:
public class JVMClass {
//常量
public final static String MAN_SEX_TYPE = "man";
//静态变量
public static String WOMAN_SEX_TYPE = "woman";
//静态方法
public static void print(Student stu) {
System.out.println("name: " + stu.getName() + "; sex:" + stu.getSexType() + "; age:" + stu.getAge()); } // 非静态方法 public void sayHello(Student stu) { System.out.println(stu.getName() + "say: hello"); }}class Student{ String name; String sexType; int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSexType() { return sexType; } public void setSexType(String sexType) { this.sexType = sexType; } public int getAge() { return age; } public void setAge(int age) { this.age = age; }}
}
//非静态方法
public void sayHello(Student stu) {
System.out.println(stu.getName() + "say: hello");
}
public static void main(String[] args) {
Student stu = new Student();
stu.setName("nick");
stu.setSexType(MAN_SEX_TYPE);
stu.setAge(20);
JVMCase jvmcase = new JVMCase();
//调用静态方法
print(stu);
//调用非静态方法
jvmcase.sayHello(stu);
}
}
class Student {
String name;
String sexType;
int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSexType() {
return sexType;
}
public void setSexType(String sexType) {
this.sexType = sexType;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
当我们运行以上程序时,JVM的处理过程如下:
1、JVM向操作系统申请内存,在获得内存空间后,JVM会根据配置参数分配堆、栈和方法区的内存大小。
2、class文件加载、验证、准备以及解析,其中准备阶段会为类的常量、静态变量分配内存,即代码中的MAN_SEX_TYPE、WOMAN_SEX_TYPE。
3、初始化(略)
4、启动main线程,执行main方法,开始执行第一行代码,此时在堆内存中创建Student对象stu,而对象的引用放在栈中。然后通过引用设置堆上对象的name、sex、age。
5、在堆内存中创建JVMCase对象jvmcase,调用非静态sayHello,此时sayHello入栈,然后通过栈上stu的引用调用堆中的stu。之后,调用静态方法print,由于是静态方法print不属于jvmcase,而属于JVMCase类,所以从静态区获取print,之后入栈,然后也是通过栈上引用调用堆中stu。