class对象和class文件_Class文件格式

 我们知道Java是一门跨平台的语言,我们编写的Java代码会被编译成中间class文件以让Java虚拟机解析运行。而Java虚拟机规范仅仅描述了抽象的Java虚拟机,在实现具体的Java虚拟机时,仅指出了设计规范。Java虚拟机的实现必须体现规范中的内容,但仅在确有必要时才应该受制于这些规范。对于完整内容,可以查看原文档,以JDK7为例,可查看https://docs.oracle.com/javase/specs/jvms/se7/html/,或者《深入理解Java虚拟机 JVM高级特性与最佳实践》一书。完整的规范主要包含以下内容:

  • 第2章:概览Java虚拟机整体架构
  • 第3章:介绍如何将Java语言编写的程序转换为虚拟机指令集
  • 第4章:定义class文件格式。它是一种与硬件和操作系统无关的二进制格式,用来表示编译后的类和接口
  • 第5章:定义了Java虚拟机启动以及类和接口的加载、链接和初始化的过程
  • 第6章:定义了Java虚拟机指令集
  • 第7章:提供了一张以操作码值为索引的Java虚拟机操作码助记表

 本文只是大概记录项目需要了解的基础概念,着重在介绍Class文件格式上,为该系列后续内容做铺垫。

 Class文件是一组以8字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑排列在class文件中,中间没有任何分割符。每个 Class 文件都是由 8 字节为单位的字节流组成,所有的 16 位、32 位和 64 位长度的数据将被构造成 2 个、4 个和 8 个 8 字节单位来表示。

 每一个Class文件对应于一个如下所示的ClassFile结构体:

6748d90d21eda9b47af63dde5463aed3.png

涉及到的内容包括:

  • magic:魔数,魔数的唯一作用是确定这个文件是否为一个能被虚拟机所接受的Class文件。魔数值固定为0xCAFEBABE,不会改变。
  • minor_version、major_version:副版本号和主版本号,minor_version和major_version的值分别表示Class文件的副、主版本。一个Java虚拟机实例只能支持特定范围内的主版本号(Mi至Mj)和0至特定范围内(0至m)的副版本号。
  • constant_pool_count:常量池计数器,constant_pool_count的值等于constant_pool表中的成员数加1。
  • constant_pool[]:常量池,constant_pool是一种表结构,它包含Class文件结构及其子结构中引用的所有字符串常量、类或接口名、字段名和其它常量。
  • access_flags:访问标志,access_flags是一种掩码标志,用于表示某个类或者接口的访问权限及基础属性。
  • this_class:类索引
  • super_class:父类索引
  • interfaces_count:接口计数器,interfaces_count的值表示当前类或接口的直接父接口数量
  • interfaces[]:接口表,在interfaces[]数组中,成员所表示的接口顺序和对应的源代码中给定的接口顺序(从左至右)一样,即interfaces[0]对应的是源代码中最左边的接口。
  • fields_count:字段计数器,fields_count的值表示当前Class文件fields[]数组的成员个数。
  • fields[]:字段表,fields[]数组描述当前类或接口声明的所有字段,但不包括从父类或父接口继承的部分。
  • methods_count:方法计数器,methods_count的值表示当前Class文件methods[]数组的成员个数。
  • methods[]:方法表,methods[]数组只描述当前类或接口中声明的方法,不包括从父类或父接口继承的方法。
  • attributes_count:属性计数器,attributes_count的值表示当前Class文件attributes表的成员个数。
  • attributes[]:属性表

 可用jdk自带的javap命令对class文件进行反编译,以查看内容,如下代码:

public class Ex { public void judgeAge(int age) { int step = 0; if (age > 18) { step++; System.out.println("a litter old"); } else { System.out.println("a litter cute"); step++; } System.out.println(step); } public static void main(String[] args) { Ex ex = new Ex(); ex.judgeAge(16); }}

执行 javap -verbose -p Ex.class的结果为

Classfile Ex.class Last modified 2019-11-29; size 788 bytes MD5 checksum 8b5d8ebf38c4441fe7150c10da31ce1b Compiled from "Ex.java"public class Ex minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPERConstant pool: #1 = Methodref #10.#31 // java/lang/Object."":()V #2 = Fieldref #32.#33 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #34 // a litter old #4 = Methodref #35.#36 // java/io/PrintStream.println:(Ljava/lang/String;)V #5 = String #37 // a litter cute #6 = Methodref #35.#38 // java/io/PrintStream.println:(I)V #7 = Class #39 // Ex #8 = Methodref #7.#31 // Ex."":()V #9 = Methodref #7.#40 // Ex.judgeAge:(I)V #10 = Class #41 // java/lang/Object #11 = Utf8  #12 = Utf8 ()V #13 = Utf8 Code #14 = Utf8 LineNumberTable #15 = Utf8 LocalVariableTable #16 = Utf8 this #17 = Utf8 LEx; #18 = Utf8 judgeAge #19 = Utf8 (I)V #20 = Utf8 age #21 = Utf8 I #22 = Utf8 step #23 = Utf8 StackMapTable #24 = Utf8 main #25 = Utf8 ([Ljava/lang/String;)V #26 = Utf8 args #27 = Utf8 [Ljava/lang/String; #28 = Utf8 ex #29 = Utf8 SourceFile #30 = Utf8 Ex.java #31 = NameAndType #11:#12 // "":()V #32 = Class #42 // java/lang/System #33 = NameAndType #43:#44 // out:Ljava/io/PrintStream; #34 = Utf8 a litter old #35 = Class #45 // java/io/PrintStream #36 = NameAndType #46:#47 // println:(Ljava/lang/String;)V #37 = Utf8 a litter cute #38 = NameAndType #46:#19 // println:(I)V #39 = Utf8 Ex #40 = NameAndType #18:#19 // judgeAge:(I)V #41 = Utf8 java/lang/Object #42 = Utf8 java/lang/System #43 = Utf8 out #44 = Utf8 Ljava/io/PrintStream; #45 = Utf8 java/io/PrintStream #46 = Utf8 println #47 = Utf8 (Ljava/lang/String;)V{ public Ex(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return LineNumberTable: line 1: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LEx; public void judgeAge(int); descriptor: (I)V flags: ACC_PUBLIC Code: stack=2, locals=3, args_size=2 0: iconst_0 1: istore_2 2: iload_1 3: bipush 18 5: if_icmple 22 8: iinc 2, 1 11: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 14: ldc #3 // String a litter old 16: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 19: goto 33 22: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 25: ldc #5 // String a litter cute 27: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 30: iinc 2, 1 33: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 36: iload_2 37: invokevirtual #6 // Method java/io/PrintStream.println:(I)V 40: return LineNumberTable: line 4: 0 line 5: 2 line 6: 8 line 7: 11 line 9: 22 line 10: 30 line 12: 33 line 13: 40 LocalVariableTable: Start Length Slot Name Signature 0 41 0 this LEx; 0 41 1 age I 2 39 2 step I StackMapTable: number_of_entries = 2 frame_type = 252 /* append */ offset_delta = 22 locals = [ int ] frame_type = 10 /* same */ public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=2, args_size=1 0: new #7 // class Ex 3: dup 4: invokespecial #8 // Method "":()V 7: astore_1 8: aload_1 9: bipush 16 11: invokevirtual #9 // Method judgeAge:(I)V 14: return LineNumberTable: line 16: 0 line 17: 8 line 18: 14 LocalVariableTable: Start Length Slot Name Signature 0 15 0 args [Ljava/lang/String; 8 7 1 ex LEx;}SourceFile: "Ex.java"

下面对后续需要接触到的几项内容做说明。

1. 数据项

 Class文件中有两种数据类型,分别是无符号数和表:

98ed6d70c4e38817b6798c95980ec951.png
  • 无符号数:属于基本数据类型,主要可以用来描述数字、索引符号、数量值或者按照UTF-8编码构成的字符串值,大小使用u1、u2、u4、u8分别表示1字节、2字节、4字节和8字节
  • 表:是由多个无符号数或者其他表作为数据项构成的复合数据类型,所有的表都习惯以“_info”结尾

2. 访问和修饰符标识

fdbc978474cae85ac1e67fe58f2d82d4.png

 带有 ACC_SYNTHETIC 标志的部分,意味着它是由编译器自己产生的而不是由程序员编写的源代码生成的。有该标志的类、属性、方法等不会在源码中显示。

3. 类型描述符

8df97907a55e6cc616bdc9e825f3c54a.png

 基本类型的描述是单个字符:

  • Z表示 boolean
  • C表示 char
  • B表示 byte
  • S表示 short
  • I 表示 int
  • F 表示 float
  • J 表示 long
  • D 表示 double
  • 一个类类型的描述符是这个类的内部名,前面加上字符 L,后面跟有一个分号。例如,String 的类型描述符为 Ljava/lang/String;。而一个数组类型的 述符是一个方括号后面跟有该数组元素类型的描述符。

4. 方法描述符

 方法描述符是一个类型描述符列表,它用一个字符串描述一个方法的参数类型和返回类型。

 方法描述符以左括号开头,然后是每个形参的类型描述,然后是一个右括号,接下来是返回类型的类型描述符,如果该方法返回void,则是 V,表示方法描述中不包含方法的名字或参数名,可看如下例子:

3d0a073712e843557bfce937e1b09c31.png

5. 指令

 Java虚拟机的指令由一个字节长度的、代表着某种特定操作含义的操作码(Opcode)以及跟随其后的零至多个代表此操作所需参数的操作数(Operands)所构成。虚拟机中许多指令并不包含操作数,只有一个操作码。

 常见的指令如下:

  • 字段访问指令:getfield,putfield,getstatic,pustatic
  • 比较指令:dcmpg,dcmpl,fcmpg,fcmpl,lcmp
  • 跳转指令:ifeq,iflt,ifle,ifne,ifgt,ifge,ifnull,ifnonnull
  • 比较条件跳转指令:ificmpeq,ificmpne,ificmplt,ificmpgt,ificmple,ificmpge,ifacmpeq,ifacmpne
  • 多条件分支跳转:tableswitch和lookupswitch
  • 无条件跳转:goto
  • 函数调用与返回指令
  • 函数调用指令:invokevirtual,invokeinterface,invokespecial,invokestatic,invokedynamic;
  • 函数返回:需要将返回值压入调用者操作数栈,需要使用xreturn指令(x可以是i,l,f,d,a或空)

 PS:笔者个人习惯使用Bytecode Outline进行反编译,这款插件输出的内容可读性会高点,上面的内容输出下:

// class version 52.0 (52)// access flags 0x21public class Ex { // compiled from: Ex.java // access flags 0x1 public ()V L0 LINENUMBER 1 L0 ALOAD 0 INVOKESPECIAL java/lang/Object. ()V RETURN L1 LOCALVARIABLE this LEx; L0 L1 0 MAXSTACK = 1 MAXLOCALS = 1 // access flags 0x1 public judgeAge(I)V L0 LINENUMBER 4 L0 ICONST_0 ISTORE 2 L1 LINENUMBER 5 L1 ILOAD 1 BIPUSH 18 IF_ICMPLE L2 L3 LINENUMBER 6 L3 IINC 2 1 L4 LINENUMBER 7 L4 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; LDC "a litter old" INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V GOTO L5 L2 LINENUMBER 9 L2 FRAME APPEND [I] GETSTATIC java/lang/System.out : Ljava/io/PrintStream; LDC "a litter cute" INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V L6 LINENUMBER 10 L6 IINC 2 1 L5 LINENUMBER 12 L5 FRAME SAME GETSTATIC java/lang/System.out : Ljava/io/PrintStream; ILOAD 2 INVOKEVIRTUAL java/io/PrintStream.println (I)V L7 LINENUMBER 13 L7 RETURN L8 LOCALVARIABLE this LEx; L0 L8 0 LOCALVARIABLE age I L0 L8 1 LOCALVARIABLE step I L1 L8 2 MAXSTACK = 2 MAXLOCALS = 3 // access flags 0x9 public static main([Ljava/lang/String;)V L0 LINENUMBER 16 L0 NEW Ex DUP INVOKESPECIAL Ex. ()V ASTORE 1 L1 LINENUMBER 17 L1 ALOAD 1 BIPUSH 16 INVOKEVIRTUAL Ex.judgeAge (I)V L2 LINENUMBER 18 L2 RETURN L3 LOCALVARIABLE args [Ljava/lang/String; L0 L3 0 LOCALVARIABLE ex LEx; L1 L3 1 MAXSTACK = 2 MAXLOCALS = 2}

更多原创内容请搜索微信公众号:啊驼(doubaotaizi)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/393613.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2018计算机应用基础考试6,2018结构工程师《计算机应用基础》试题(6)

大家做好准备迎接2018考试了吗?出国留学网为您整理了“2018结构工程师《计算机应用基础》试题(6)”,跟着出国留学网来了解一下吧。要相信只要自己有足够的实力,无论考什么都不会害怕!2018结构工程师《计算机应用基础》试题(6)1、下列存储器中&#xff0…

leetcode1282. 用户分组(贪心算法)

有 n 位用户参加活动,他们的 ID 从 0 到 n - 1,每位用户都 恰好 属于某一用户组。给你一个长度为 n 的数组 groupSizes,其中包含每位用户所处的用户组的大小,请你返回用户分组情况(存在的用户组以及每个组中用户的 ID&…

mysql解锁_mysql 解锁

show OPEN TABLES where In_use > 0;show processlist;show status like Table%;show status like %lock%;show OPEN TABLES where In_use > 0;//1.查看当前数据库锁表的情况SELECT * FROM information_schema.INNODB_TRX;//2.杀掉查询结果中锁表的trx_mysql_…

强制换行和禁止换行

强制换行:word-break: break-all; 只对英文起作用,以字母作为换行依据word-wrap: break-word; 只对英文起作用,以单词作为换行依据white-space: pre-wrap; 只对中文起作用,强制换行禁止换行:white-space: now…

构建自己的简单微服务架构(开源)

构建自己的简单微服务架构(开源) 原文:构建自己的简单微服务架构(开源)前言 本篇仅作引导,内容较多,如果阅读不方便,可以使用电脑打开我们的文档官网进行阅读。如下图所示&#…

职业生涯愿景计算机,职业生涯愿景

《职业生涯愿景》由会员分享,可在线阅读,更多相关《职业生涯愿景(10页珍藏版)》请在人人文库网上搜索。1、职业生涯愿景职业生涯愿景设备安装技术是掌握本专业必需的基本理论知识,具有设备制造、安装、调试、管理、设计。施工方案编制的专业技…

leetcode881. 救生艇(贪心算法加双指针)

第 i 个人的体重为 people[i],每艘船可以承载的最大重量为 limit。 每艘船最多可同时载两人,但条件是这些人的重量之和最多为 limit。 返回载到每一个人所需的最小船数。(保证每个人都能被船载)。 示例 1: 输入:people [1,2]…

react避免子组件渲染_如何与React一起使用正确的方法来避免一些常见的陷阱

react避免子组件渲染One thing I hear quite often is “Let’s go for Redux” in our new React app. It helps you scale, and the App data shouldn’t be in React local state because it is inefficient. Or when you call an API and while the promise is pending, th…

[转载]Spring配置文件详解一:

2019独角兽企业重金招聘Python工程师标准>>> 原文地址&#xff1a;Spring配置文件详解一&#xff1a;<context:annotation-config/>与<context:component-scan base-package"com.xx 作者&#xff1a;爱情随遇而安 <context:annotation-config/>…

mysql 8.0.16修改root密码_mysql 8.0.16 winx64及Linux修改root用户密码 的方法

连接数据库等基础操作请自行解决哈&#xff0c;本篇是重点记录如何改密码。一、查询用户密码:查询用户密码命令&#xff1a;select host, user, authentication_string from mysql.user ;host&#xff1a;允许用户登录的ip‘位置%表示可以远程&#xff1b;user&#xff1a;当前…

舞台设计

舞台设计 #include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<cstdio> #include<queue> using namespace std;int ucol[1005],dcol[1005],lrow[1005],rrow[1005]; int numr[1005],numc[1005]; int a[100…

LoadRunner11支持的浏览器小结

LoadRunner11支持的浏览器小结转载于:https://www.cnblogs.com/zwh-Seeking/articles/11060154.html

手机计算机的隐藏小技巧,涨知识!MIUI计算器原来有这么多隐藏小技巧,最后一个绝对想不到...

原标题&#xff1a;涨知识&#xff01;MIUI计算器原来有这么多隐藏小技巧&#xff0c;最后一个绝对想不到计算器除了我们需要进行日常的计算以外&#xff0c;几乎是用不到的。但是MIUI中的计算器与普通计算器可不同&#xff0c;里面的隐藏小技巧足以让你震惊到&#xff0c;那么…

如何使用JavaScript中的工厂函数构建可靠的对象

Discover Functional JavaScript was named one of the best new Functional Programming books by BookAuthority!“发现功能JavaScript”被BookAuthority评为最佳新功能编程书籍之一 &#xff01; I suggest to take into consideration these ideas for building reliable …

leetcode99. 恢复二叉搜索树(优先队列)

二叉搜索树中的两个节点被错误地交换。请在不改变其结构的情况下&#xff0c;恢复这棵树。示例 1:输入: [1,3,null,null,2]1/3\2输出: [3,1,null,null,2]3/1\2代码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* …

Android零基础入门第83节:Activity间数据传递方法汇总

2019独角兽企业重金招聘Python工程师标准>>> 在Activity间传递的数据一般比较简单&#xff0c;但是有时候实际开发中也会传一些比较复杂的数据&#xff0c;本节一起来学习更多Activity间数据的传递。 一、常用数据类型 在前面几节我们只学习了一些常用类型的数据传递…

mysql gz 安装_Linux下安装mysql 5.7.17.tar.gz的教程详解

1.创建MySQL组和mysql用户groupadd mysqluseradd -r -g mysql mysql2.拷贝&#xff1a;cp -R mysql-5.7.16-linux-glibc2.5-i686 /usr/local/mysql3.创建data目录mkdir /usr/local/mysql/data3.安装数据库切换到/usr/loca/mysql目录下cd /usr/local/mysql修改当前目录的所有者为…

02-c#基础之01-基础语法(一)

1.注释符 1&#xff09;注销 2) 解释 2.C#中的3种注释符 1&#xff09;单行注释// 2)多行注释/*要注释的内容*/ 3)文档注释///多用来解释类或者方法 2.VS中的快捷键 转载于:https://www.cnblogs.com/yoyo-524/p/6502827.html

day01_初识python

编译型&#xff1a;一次性将所有的代码编译呈二进制文件。C/C 优点&#xff1a;执行效率高 缺点&#xff1a;开发速度慢&#xff0c;不能跨平台 解释型&#xff1a;当程序运行时&#xff0c;从上到下一行一行的解释为二进制文件 优点&#xff1a;开发效率快&#xff0c;可以跨平…

leetcode1414. 和为 K 的最少斐波那契数字数目(贪心算法)

给你数字 k &#xff0c;请你返回和为 k 的斐波那契数字的最少数目&#xff0c;其中&#xff0c;每个斐波那契数字都可以被使用多次。 斐波那契数字定义为&#xff1a; F1 1 F2 1 Fn Fn-1 Fn-2 &#xff0c; 其中 n > 2 。 数据保证对于给定的 k &#xff0c;一定能找…