41.JVM方法区的内部结构(方法区中存储的是什么)
1.方法区内部结构
Java
代码被编译成字节码文件之后,通过类加载器被加载到运行时数据区。其中,方法区主要存储的是类型的相关信息以及运行时常量池。对于字符串常量,根据JDK
版本的不同,有的放到了方法区,有的没有。
方法区中存放的是类型信息、常量、静态变量、即时编译器编译后的代码缓存、域信息、方法信息等。随着JDK的发展,方法区中存放的内容也在发生变化。并不绝对。通常情况下放的是这些内容。
1.类型信息
2.域信息 ==>
成员变量信息
3.方法信息
例子:下面是一个Java
程序的字节码文件通过javap
反编译之后得到的输出。
class文件中的类型信息、域信息、方法信息都会被类加载器加载到方法区中。
Last modified 2020-4-22; size 1626 bytes MD5 checksum 69643a16925bb67a96f54050375c75d0 Compiled from "MethodInnerStrucTest.java" //类型信息会被加载到方法区 public class com.atguigu.java.MethodInnerStrucTest extends java.lang.Object // 类的全限定名以及父类 implements java.lang.Comparable<java.lang.String>, java.io.Serializable //类实现的接口信息 minor version: 0 major version: 51 flags: ACC_PUBLIC, ACC_SUPER // 类的权限修饰符 Constant pool: #1 = Methodref #18.#52 // java/lang/Object."<init>":()V #2 = Fieldref #17.#53 // com/atguigu/java/MethodInnerStrucTest.num:I #3 = Fieldref #54.#55 // java/lang/System.out:Ljava/io/PrintStream; ... { //域信息会被加载到方法区 public int num; // 域名称 descriptor: I // 域类型 flags: ACC_PUBLIC // 域权限 private static java.lang.String str; descriptor: Ljava/lang/String; flags: ACC_PRIVATE, ACC_STATIC //方法信息会被加载到方法区 public com.atguigu.java.MethodInnerStrucTest(); // 方法名称 descriptor: ()V //方法参数及方法返回值类型 flags: ACC_PUBLIC //方法权限修饰符 Code: //方法对应的字节码 stack=2, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: bipush 10 7: putfield #2 // Field num:I 10: return LineNumberTable: line 10: 0 line 12: 4 LocalVariableTable: Start Length Slot Name Signature 0 11 0 this Lcom/atguigu/java/MethodInnerStrucTest; ...... } Signature: #49 // Ljava/lang/Object;Ljava/lang/Comparable<Ljava/lang/String;>;Ljava/io/Serializable; SourceFile: "MethodInnerStrucTest.java"
2.non-final
的类变量与final
的类变量初始化的时间
non-final
的类变量:就是static
的成员变量。final
的类变量:就是static final
的成员变量。
初始化的区别:初始化的时间不同,non-final
的类变量在类加载的第二个阶段(链接阶段)的准备阶段被赋默认的初始值,然后再类加载的第三个阶段(初始化阶段)被显示初始化(也就是赋值为代码中写的值)。
比如: 定义一个成员变量a
, public static int a = 7;
a
在链接阶段的准备阶段被赋默认值0
;然后再初始化阶段被显示初始化为7
。
final
的类变量是在编译阶段就被显示初始化了。
比如:定义一个成员变量, public static final int a = 7;
,a
在代码被编译成字节码文件的时候就被赋值为7
了。