《深入理解Java虚拟机》书中对方法区(Method Area)存储内容描述如下:它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等。
类型信息
对每个加载的类型(类class、接口interface、枚举enum、注解annotation),JVm必须在方法区中存储以下类型信息:
-
这个类型的完整有效名称(全名=包名.类名)
-
这个类型直接父类的完整有效名(对于interface或是java.lang.object,都没有父类)
-
这个类型的修饰符(public,abstract,final的某个子集)
-
这个类型直接接口的一个有序列表
域信息(属性)
JVM必须在方法区中保存类型的所有域的相关信息以及域的声明顺序。
域的相关信息包括:域名称、域类型、域修饰符(public,private,protected,static,final,volatile,transient的某个子集)
方法(Method)信息
JVM必须保存所有方法的以下信息,同域信息一样包括声明顺序:
-
方法名称
-
方法的返回类型(或void)
-
方法参数的数量和类型(按顺序)
-
方法的修饰符(public,private,protected,static,final,synchronized,native,abstract的一个子集)
-
方法的字节码(bytecodes)、操作数栈、局部变量表及大小(abstract和native方法除外)
-
异常表(abstract和native方法除外)
方法区中还记录着每个类是被哪个类型的类加载器加载的,类加载器也记录着它加载过谁,相互记录
non-final的类变量
静态变量和类关联在一起,随着类的加载而加载,他们成为类数据在逻辑上的一部分
类变量被类的所有实例共享,即使没有类实例时,你也可以访问它。
public class MethodAreaTest {
public static void main(String[] args) {
Order order = null;
order.hello();
System.out.println(order.count);
}
}
class Order {
public static int count = 1;
public static final int number = 2;
public static void hello() {
System.out.println("hello!");
}
}
注意此处,invokestatic,调用的还是类方法,即与赋值无关
全局常量
全局常量就是使用 static final 进行修饰
被声明为final的类变量的处理方法则不同,每个全局常量在编译的时候就会被分配了,即在被编译成class文件的时候就已经被赋值了。