文章目录
static、final、volatile关键字
static:static修饰的变量被所有类实例共享,静态变量在其所在类被加载时进行初始化,静态方法中不能引用非静态变量或函数
final:final修饰的变量不可修改(基本类型值不能修改,引用类型引用不可修改),final修饰的方法,不可重写、不可继承
volatile:volatile修饰的成员变量在每次被线程访问时,都从主内存中重新读取该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到主内存
synchronized:Synchronized关键字就是用于代码同步,用于控制多线程同步访问同一变量或方法
这些Java关键字的作用,大家或多或少都听过,但是为什么会有这种效果呢?本文从Java字节码层面做简单分析
那么什么又是字节码呢?
什么是字节码
Java之所以可以“一次编译,到处运行”,一是因为JVM针对各种操作系统、平台都进行了定制,二是因为无论在什么平台,都可以编译生成固定格式的字节码(.class文件)供JVM使用。因此,也可以看出字节码对于Java生态的重要性。之所以被称之为字节码,是因为字节码文件由十六进制值组成,而JVM以两个十六进制值为一组,即以字节为单位进行读取。
.class文件就是Java代码编译后产生的字节码文件,看下具体实例
用Sublime Text以文本文件打开,显示如下
Javap命令查看字节码文件
先写一段如下代码,非常简单
定义一个抽象类JavaTestController
变量a为静态成员变量(int)
变量b为普通成员变量(int)
变量c为volatile修饰的变量(int)
变量d为final修饰的变量(String)
变量s为字符串(String)
变量o为Object类型(Object)
public abstract class JavaTestController {
public static int a = 1;
public int b = 2;
public volatile int c = 3;
public final int d = 4;
private String s = "5";
private Object o = new Object();
public void test() {
System.out.println("1");
}
}
那么问题来了,文本形式看到.class文件全是十六进制的代码,有没更人性化的展示呢?
javap是jdk自带的反解析工具。它的作用就是根据class字节码文件,反解析出当前类对应的code区(汇编指令)、本地变量表、异常表和代码行偏移量映射表、常量池等等信息
命令如下
javap -verbose class文件路径
看下这段代码使用javap命令输出的的字节码
Classfile /Users/chenyin/IdeaProjects/spring-boot-api-project-seed/target/classes/com/company/project/biz/controller/JavaTestController.class
Last modified 2019-9-19; size 883 bytes
MD5 checksum 9ac63f28ebe7c6a65dd6c5a12913e064
Compiled from "JavaTestController.java"
public abstract class com.company.project.biz.controller.JavaTestController
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER, ACC_ABSTRACT
Constant pool:
#1 = Methodref #7.#36 // java/lang/Object."<init>":()V
#2 = Fieldref #13.#37 // com/company/project/biz/controller/JavaTestController.b:I
#3 = Fieldref #13.#38 // com/company/project/biz/controller/JavaTestController.c:I
#4 = Fieldref #13.#39 // com/company/project/biz/controller/JavaTestController.d:I
#5 = String #40 // 5
#6 = Fieldref #13.#41 // com/company/project/biz/controller/JavaTestController.s:Ljava/lang/String;
#7 = Class #42 // java/lang/Object
#8 = Fieldref #13.#43 // com/company/project/biz/controller/JavaTestController.o:Ljava/lang/Object;
#9 = Fieldref #44.#45 // java/lang/System.out:Ljava/io/PrintStream;
#10 = String #46 // 1
#11 = Methodref #47.#48 // java/io/PrintStream.println:(Ljava/lang/String;)V
#12 = Fieldref #13.#49 // com/company/project/biz/controller/JavaTestController.a:I
#13 = Class #50 // com/company/project/biz/controller/JavaTestController
#14 = Utf8 a
#15 = Utf8 I
#16 = Utf8 b
#17 = Utf8 c
#18 = Utf8 d
#19 = Utf8