JVM 字节码(四)静态方法、构造代码、this 以及 synchronized 关键字
JVM 字节码(四)静态方法、构造代码、this 以及 synchronized 关键字
一、静态代码
public class ByteCodeStatic {
private static final String DEFAULT_VALUE = "default_value";
private static String str = DEFAULT_VALUE;
static {
System.out.println("hello");
}
}
编译后查看对应的字节码,生成了两个方法 和
<cinit>静态赋值和静态代码块的集合,执行顺序和代码一致。注意不包含常量的赋值。<init>构造方法,包含普通变量值赋值和构造函数。
cinit 的代码块如下,不包含常量 DEFAULT_VALUE 的赋值,这是通过常量值(ConstantValue)进行赋值的。
0 ldc #3 <default_value>
2 putstatic #4 <com/github/binarylei/jvm/bytecode/ByteCodeStatic.str>
5 getstatic #5 <java/lang/System.out>
8 ldc #6 <hello>
10 invokevirtual #7 <java/io/PrintStream.println>
13 return
但常量就一定是通过 ConstantValue 赋值吗?如果编译期无法确定常量的值那也是需要通过静态代码块来赋值的,也就是会出现在 cinit 代码中。
public class ByteCodeStatic {
private static final String DEFAULT_VALUE = new String("default_value");
private static String str = DEFAULT_VALUE;
static {
System.out.println("hello");
}
}
将 DEFAULT_VALUE 的值修改为一个对象,这个对象需要在运行期才能确定值,重新编译后的指定集如,很明显出现了常量的赋值语句(前五个语句):
0 new #2 <java/lang/String>
3 dup
4 ldc #3 <default_value>
6 invokespecial #4 <java/lang/String.<init>>
9 putstatic #5 <com/github/binarylei/jvm/bytecode/ByteCodeStatic.DEFAULT_VALUE>
12 getstatic #5 <com/github/binarylei/jvm/bytecode/ByteCodeStatic.DEFAULT_VALUE>
15 putstatic #6 <com/github/binarylei/jvm/bytecode/ByteCodeStatic.str>
18 getstatic #7 <java/lang/System.out>
21 ldc #8 <hello>
23 invokevirtual #9 <java/io/PrintStream.println>
26 return
二、构造方法
public class ByteCodeConstructor {
private String str = "binarylei";
{
System.out.println("hello");
}
public ByteCodeConstructor() {
}
public ByteCodeConstructor(String str) {
this.str = str;
}
}
编译后查看对应的字节码,生成了两个 构造方法。
第一个构造器:
0 aload_0 // this 参数(所有的非静态方法都包含这个参数)
1 invokespecial #1 <java/lang/Object.<init>> // 执行父类构造方法
4 aload_0
5 ldc #2 <binarylei> // 加载字符串 binarylei
7 putfield #3 <com/github/binarylei/jvm/bytecode/ByteCodeConstructor.str> // str 赋值
10 getstatic #4 <java/lang/System.out>
13 ldc #5 <hello>
15 invokevirtual #6 <java/io/PrintStream.println> // System.out.println("hello");
18 return
第二个构造器:
0 aload_0
1 invokespecial #1 <java/lang/Object.<init>>
4 aload_0
5 ldc #2 <binarylei>
7 putfield #3 <com/github/binarylei/jvm/bytecode/ByteCodeConstructor.str>
10 getstatic #4 <java/lang/System.out>
13 ldc #5 <hello>
15 invokevirtual #6 <java/io/PrintStream.println>
18 aload_0 // this 参数(所有的非静态方法都包含这个参数)
19 aload_1 // str 参数
20 putfield #3 <com/github/binarylei/jvm/bytecode/ByteCodeConstructor.str>
23 return
总结: 构造方法会将普通常量和普通代码块整合到其构造器字节块中,每个构造方法都会拼凑一份。
三、this 参数
对于 Java 类中的每一个实例方法(非 static 方法),其在编译后所生成的字节码中,方法参数的数量总是会比源代码中方法的数量多一个(this),它位于方法的第一个参数位置。 这样,我们可以在 Java 的实例方法中使用 this 来去访问当前对象的属性以及其方法。
这个操作是在编译期间完成的,即由 Javac 编译器在编译的时候对 this 的访问转化为一个普通实例方法参数的访问;接下来在运行期由 JVM 在调用实例方法时,自动向实例方法传入该 this 参数,所以,在实例方法的局部变量表中,至少会有一个指向当前对象的局部变量。
四、synchronized
public void test2() {
synchronized (this) {
}
}
编译后字节码如下:
0 aload_0
1 dup
2 astore_1
3 monitorenter
4 aload_1
5 monitorexit
6 goto 14 (+8)
9 astore_2
10 aload_1
11 monitorexit
12 aload_2
13 athrow
14 return
monitorenter 和 monitorexit 获取锁和释放锁
参考:
- 周志明,深入理解Java虚拟机 - 第 6 章:类文件结构
- Java 反编译工具 - jclasslib(比 javap -v 信息更详细,可以在 IDEA 插件中直接下载)
JVM 字节码(四)静态方法、构造代码、this 以及 synchronized 关键字的更多相关文章
- Java finally语句到底是在return之前还是之后执行(JVM字节码分析及内部体系结构)?
之前看了一篇关于"Java finally语句到底是在return之前还是之后执行?"这样的博客,看到兴致处,突然博客里的一个测试用例让我产生了疑惑. 测试用例如下: public ...
- JVM总结(五):JVM字节码执行引擎
JVM字节码执行引擎 运行时栈帧结构 局部变量表 操作数栈 动态连接 方法返回地址 附加信息 方法调用 解析 分派 –“重载”和“重写”的实现 静态分派 动态分派 单分派和多分派 JVM动态分派的实现 ...
- JVM 字节码执行实例分析
前言 最近在看<Java 虚拟机规范>和<深入理解JVM虚拟机>,对于字节码的执行有了进一步的了解.字节码就像是汇编语言,是 JVM 的指令集.下面我们先对 JVM 执行引擎做 ...
- JVM 字节码(二)方法表详解
JVM 字节码(二)方法表和属性表 上一节中对 ClassFile 的整体进行了五个详细的说明, 本节围绕 ClassFile 最重要的一个内容 - 方法表的 Code 属性展开 ,更多 JVM Me ...
- JVM 字节码指令手册 - 查看 Java 字节码
JVM 字节码指令手册 - 查看 Java 字节码 jdk 进行的编译生成的 .class 是 16 进制数据文件,不利于学习分析.通过下命令 javap -c Demo.class > Dem ...
- 一夜搞懂 | JVM 字节码执行引擎
前言 本文已经收录到我的 Github 个人博客,欢迎大佬们光临寒舍: 我的 GIthub 博客 学习导图 一.为什么要学习字节码执行引擎? 代码编译的结果从本地机器码转变为字节码,是存储格式发展的一 ...
- 从jvm字节码指令看i=i++和i=++i的区别
1. 场景的产生 先来看下下面代码展示的两个场景 @Testvoid testIPP() { int i = 0; for (int j = 0; j < 10; j++) { i = i++; ...
- 从JVM字节码执行看重载和重写
Java 重写(Override)与重载(Overload) 重写(Override) 重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变.即外壳不变,核心重写! 重写的 ...
- JVM 字节码(三)异常在字节码中的处理(catch 和 throws)
JVM 字节码(三)异常在字节码中的处理(catch 和 throws) 在 ClassFile 中到底是如何处理异常的呢? 一.代码块异常 catch catch 中的异常代码块在异常是如何处理的呢 ...
随机推荐
- 使用JAVA实现的一个简单IOC注入实例
https://blog.csdn.net/echoshinian100/article/details/77977823 欲登高而望远,勿筑台于流沙 RSS订阅 原 使用JAVA实现的一个简单IOC ...
- Python 模块collections
1.深入理解python中的tuple的功能 基本特性 # 可迭代 name_tuple = ('0bug', '1bug', '2bug') for name in name_tuple: prin ...
- 记一次nginx403错误
同事开发微信小程序,小程序通过API接口调用我们的人脸比对API,但是一直是提示403,通过查看查看nginx日志,发现请求并没有转发出去,转发出去的请求,应该是301,重定向, 然后就开始在ngin ...
- Java String对象的问题 String s="a"+"b"+"c"+"d"
1, String s="a"+"b"+"c"+"d"创建了几个对象(假设之前串池是空的) 2,StringBuilde ...
- SpringCloud和Springboot
SpringBoot+SpringCloud+SpringMVC+SpringData 我们把这种架构也称之为spring全家桶 什么是SpringCloudSpring Cloud是一系列框架的有序 ...
- 廖雪峰Java6 IO编程-3Reader和Writer-2Writer
1.java.io.Writer和java.io.OutputStream的区别 OutputStream Writer 字节流,以byte为单位 字符流,以char为单位 写入字节(0-255):v ...
- python之路——7
王二学习python的笔记以及记录,如有雷同,那也没事,欢迎交流,wx:wyb199594 复习 1. 小数据池 int -5---256 str 特殊字符 *202. ASCII码 8位 1字节 - ...
- Power Designer 转C#实体类方法
1.打开Power Designer菜单 Tools,选择如图 2.弹出方框中选择PD安装目录下的如图地址 3.object language选择正确目录后,可选如图语言,如C#.再填写name ...
- U3D学习14-一阶段学习总结
一.UGUI界面拖拽 1.物品类中继承以下5个接口 命名空间: UnityEngine.EventSystem; IBeingDragHandler (OnBeingDrag) IDragHandle ...
- 学习 MeteoInfo二次开发教程(二)
1.注意TSB_Select_Click等几个名称要改为toolStripButton2_Click等. 2.以下代码的位置与public Form1()函数并行. ToolStripButton _ ...