JAVA int a = 1 中发生了什么
测试代码
javac TestCode.java
public class TestCode { public static void main(String[] args) { int aaaa = 1; aaaa = 2; } }
反编译
javap -v -p -l TestCode(l是小写的L)
注解:javap是jdk自带的反解析工具。作用是根据class字节码文件,反解析出当前类对应的code区(汇编指令)、本地变量表、异常表和代码行偏移量映射表、常量池等等信息。
Classfile xxxxx/com/code/baseCode/TestCode.class Last modified 2021-11-21; size 436 bytes MD5 checksum c2864ab4f514372ff51ed92e384bb437 Compiled from "TestCode.java" public class com.code.baseCode.TestCode minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #3.#19 // java/lang/Object."<init>":()V #2 = Class #20 // com/code/baseCode/TestCode #3 = Class #21 // java/lang/Object #4 = Utf8 <init> #5 = Utf8 ()V #6 = Utf8 Code #7 = Utf8 LineNumberTable #8 = Utf8 LocalVariableTable #9 = Utf8 this #10 = Utf8 Lcom/code/baseCode/TestCode; #11 = Utf8 main #12 = Utf8 ([Ljava/lang/String;)V #13 = Utf8 args #14 = Utf8 [Ljava/lang/String; #15 = Utf8 aaaa #16 = Utf8 I #17 = Utf8 SourceFile #18 = Utf8 TestCode.java #19 = NameAndType #4:#5 // "<init>":()V #20 = Utf8 com/code/baseCode/TestCode #21 = Utf8 java/lang/Object { public com.code.baseCode.TestCode(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 8: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/code/baseCode/TestCode; public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=2, args_size=1 0: iconst_1 1: istore_1 2: iconst_2 3: istore_1 4: return LineNumberTable: line 11: 0 line 12: 2 line 52: 4 LocalVariableTable: Start Length Slot Name Signature 0 5 0 args [Ljava/lang/String; 2 3 1 aaaa I } SourceFile: "TestCode.java"
反编译后,会发现aaaa存在于Constant pool(常量池)和LocalVariableTable(本地变量表)中
常量池解释
JVM中有Class常量池、运行时常量池、全局字符串常量池、基本类型包装类常量池。
-
Class常量池:主要存放字面量和符号引用。 详情可看字面量,符号引用,直接引用究竟是什么?
-
字面量就是固定值,int a = 1,String a = "abc",其中1和abc就是字面量,但java中字面量必须是final修饰
-
由于在编译过程中并不知道每个类的地址,因为可能这个类还没有加载,所以如果你在一个类中引用了另一个类,那么你完全无法知道他的内存地址,那怎么办,我们只能用他的类名作为符号引用,在类加载完后用这个符号引用去获取他的内存地址。
-
-
运行时常量池:运行时常量池部分数据是来自于Class常量池,其具有动态性。在Class常量池中存储着字面量和符号引用,其中符号引用会在加载时,将Class中字节流代表的静态存储转换为方法区的运行时数据结构。不同的类用同一个运行时常量池。
-
字符串常量池:JVM所维护的一个字符串实例的引用表。运行时常量池在方法区中,JDK1.7后,字符串常量池移到了堆中。
-
java中基本类型的包装类的大部分都实现了常量池技术,这些类是Byte,Short,Integer,Long,Character,Boolean,另外两种浮点数类型的包装类则没有实现。另外上面这5种整型的包装类也只是在对应值小于等于127时才可使用对象池,也即对象不负责创建和管理大于127的这些类的对象。
上面JVM常量池介绍信息来自于
终于搞懂了Java 8 的内存结构,再也不纠结方法区和常量池了!! - 掘金
jvm中class文件常量池中存放了哪些信息?/常量池为什么有变量名称呢?
JVM中Class文件常量池中存放了哪些信息_wenpan的博客-CSDN博客_jvm常量池存放哪些东西
局部变量表和操作数栈?
图片解释
java1.8的内存布局
在编译后内存情况
类文件结构:类文件结构 - 掘金
运行时发生情况
其中java byte code为
如何查看Java bytecode指令?
https://en.wikipedia.org/wiki/List_of_Java_bytecode_instructions
Jvm系列3—字节码指令 - Gityuan博客 | 袁辉辉的技术博客
上面注意的地方是,变量1指的是LocalVariableTable中的第一个变量,也就是aaaa。
iconst_1
istore_1
iconst_2
istore_1
结尾
上述是基础数据类型的情况,后续出String类型,以及包装类型的情况