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,一经查实,立即删除!

相关文章

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

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

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

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

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

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

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

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

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

四五六年级计算机教学计划,五六年级信息技术教学计划

五六年级信息技术教学计划一、大纲对本册教材的要求作为小学阶段的信息技术课程&#xff0c;应以学生对计算机的学习心理、学习行为和学习方法为背景&#xff0c;把计算机基础知识和计算机最新应用融于一体&#xff0c;使之既体现信息技术学科的教学理论&#xff0c;又吸收现代…

阿里巴巴旗下平台口碑推出无人收银技术,改造便利店市场;重庆法院运用 AI 探索“智能判案”...

阿里巴巴旗下平台口碑推出无人收银技术&#xff0c;改造便利店市场 雷锋网消息 阿里巴巴旗下本地生活服务平台口碑今日宣布在上海新兴便利店品牌24鲜上线无人收银技术。消费者只要打开支付宝&#xff0c;扫一扫想要购买的商品的条形码&#xff0c;就可以自助提交订单完成支付。…

如何使用射手影音寻找字幕

我们以"理智与情感"Sense and Sensibility为例&#xff0c;在迅雷搜索了下载&#xff0c;结果到了99%就不动了&#xff0c;由于是字幕文件&#xff0c;不能直接把TD的后缀去掉看影片&#xff0c;但是影片已经下载完成&#xff0c;所以我们使用射手影音播放该电影。&a…

C语言第二次博客作业---分支结构

一、PTA实验作业 题目1&#xff1a;计算分段函数[2] 本题目要求计算下列分段函数f(x)的值&#xff1a; 1.实验代码 double x,result;scanf("%lf",&x);if(x>0){resultsqrt(x);}else{resultpow(x1,2)2*x1/x;}printf("f(%.2f) %.2f",x,result); 2 设计…

OSChina 周四乱弹 ——妹子喜欢的是程序员 这是标准……

2019独角兽企业重金招聘Python工程师标准>>> Osc乱弹歌单&#xff08;2017&#xff09;请戳&#xff08;这里&#xff09; 【今日歌曲】 一叶孤鸿 &#xff1a;分享Nanaka的单曲《いのちの名前&#xff08;Cover 木村弓&#xff09;》 《いのちの名前&#xff08;C…

xp系统sql服务器怎么找,SQL文件在winxp系统下怎么打开

很多用户不知道SQL文件是什么?SQL文件怎么打开?我们存储数据时候经常会遇到SQL文件&#xff0c;如果你不知道WinXP系统SQL文件是什么以及怎么打开的话&#xff0c;那就赶紧看看小编整理的以下文章内容吧!SQL文件是什么?学习编程的同学可能都知道SQL是一种高级的非过程化的编…

Silverlight 设计器加载错误

每次打开silverlight页面出如下错误 然后设计器不能将页面加载出来 最后找了蛮多资料的 感觉这个原因有可能&#xff1a;“控制面板的添加删除程序那里&#xff0c;选中Microsoft Silverlight&#xff0c;看看他的版本&#xff0c;是否与所装的SDK的版本号一致。就算两个版本号…

mysql索引优化实际例子_MySQL索引优化的实际案例分析

Order by desc/asc limit M是我在mysql sql优化中经常遇到的一种场景&#xff0c;其优化原理也非常的简单&#xff0c;就是利用索引的有序性&#xff0c;优化器沿着索引的顺序扫描&#xff0c;在扫描到符合条件的M行数据后&#xff0c;停止扫描&#xff1b;看起来非常的简单&am…

阿里云视频点播解决方案使用教程

2019独角兽企业重金招聘Python工程师标准>>> 课程介绍 视频点播&#xff08;ApsaraVideo for VoD&#xff0c;简称VoD&#xff09;是集视频音视频采集、编辑、上传、自动化转码处理、媒体资源管理、分发加速于一体的一站式音视频点播解决方案。 产品详情&#xff1a…

云服务器安装操作系统后如何连接,服务器如何安装操作系统

服务器如何安装操作系统 内容精选换一换如果您需要使用毕昇编译器&#xff0c;则需要先在服务端安装毕昇编译器。毕昇编译器基于开源LLVM开发&#xff0c;并进行了优化和改进&#xff0c;同时将flang作为默认的Fortran语言前端编译器&#xff0c;是针对鲲鹏平台的高性能编译器。…

python 0基础起步学习day2

元组&#xff1a;戴上了枷锁的列表 元组是不可改变的&#xff0c;元组是不能随意改变内部的元素的 元组和列表很像&#xff0c;它可以看成是不可修改的列表 所以创建元祖逗号是关键 因为(8,)是元组&#xff0c;这里*就不再是乘号&#xff0c;而是重复拷贝符【重复操作符】 直接…

dp 1.4协议_浅析关于HDMI接口与DP接口

显示器现在主流已经为HDMI接口与DP接口&#xff0c;那么这些接口都有什么区别&#xff0c;以下表格会大致做个区分&#xff0c;建议优先使用DP接口。&#xff08;HDMI2.1接口目前仅发布协议&#xff0c;尚未大规模商用在高清电视机上有部分应用&#xff0c;Mini DP接口版本为DP…

Apache的虚拟主机配置

虚拟主机配置一般可以分为&#xff1a;基于域名基于端口基于IP配置虚拟主机检查防火墙&#xff0c;端口是否打开apache的配置文件。service iptables status #查看防火墙netstat -anp | grep 8021 #端口是必须要考虑的问题locate httpd.confmkdir -p /usr/local/apache/conf/ex…

oracle 的使用

一. docker 模式下进入数据库 ubuntujiang:~$ sudo docker ps -a sudo: unable to resolve host jiang CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS …

sql number转varchar_MySQL 指南之 SQL 语句基础

个人所有文章整理在此篇&#xff0c;将陆续更新收录:知无涯&#xff0c;行者之路莫言终(我的编程之路)零、结构化查询语言&#xff1a;SQL(Structured Query Language)DDL 数据定义语言 管理库&#xff0c;表DML 数据操作语言 增删改查 DCL 数据控制语言 数据控制&#xff0c;权…