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 中的异常代码块在异常是如何处理的呢 ...
随机推荐
- windows7 64位安装tensorflow 1.4.0 CPU版本
机器学习和深度学习真是新生代的宠儿,我也被安排来搞这个了,这下是真的从0开始了.看了几天ppt,想跑跑代码试试,装个环境. 都说tensorflow很火很好用,反正我什么也不懂,准备把这些框架一个一个 ...
- 【python】dist-packages和site-packages的区别
一.dist-packages和site-packages的区别 sudo apt-get install 安装的package存放在/usr/lib/python2./dist-packages目录 ...
- 关于spring boot在IDE工具中可以启动成功,但是打成jar包以及运行jar包失败的问题
1. 运行jar包报错,如下图: 2. 首先,找到pom.xml,把下面的build块中的内容改成如下所示: 3. 然后,请千万不要用Intellij idea来打包项目为Jar,你应该来到项目的根目 ...
- Master公式计算递归时间复杂度
我们在算递归算法的时间复杂度时,Master定理为我们提供了很强大的便利! Master公式在我们的面试编程算法中除了BFPRT算法的复杂度计算不了之外,其他都可以准确计算! 这里用求数组最大值的递归 ...
- Mysql TIMESTAMPDIFF测试
select TIMESTAMPDIFF(DAY, '2015-04-20 00:00:00', '2015-04-20 23:59:59');# 只要不足24小时 为0天 select TIMEST ...
- python:选房抽签小工具
1.房间号和姓名写在house_name.xls的house标签页中[注意!名字均不要改动]2.运行house.py3.当前同目录下会生成result.xls,即为结果:程序运行过程中不要打开该文件, ...
- JAVA Maven 安装 jar 包到本地仓库,以 Oracle11g 的访问包 为例
maven 作为 java 的首选包管理工具,使我们在创建和维护项目的时候变得十分简单,但是 maven 仓库并不是拥有的一切 jar 包的, 很多 jar 包由于收费或者版权什么的其他原因,并不存在 ...
- 用java语言构建一个网络服务器,实现客户端和服务器之间通信,实现客户端拥有独立线程,互不干扰
服务器: 1.与客户端的交流手段多是I/O流的方式 2.对接的方式是Socket套接字,套接字通过IP地址和端口号来建立连接 3.(曾经十分影响理解的点)服务器发出的输出流的所有信息都会成为客户端的输 ...
- com.mysql.jdbc.Connection.isValid(I)Z
spring boot项目 运行提示这个错误的时候 只需要配置
- Java学习笔记(十五):import关键字