这是Java基础篇(JVM)的第一篇文章,本来想先说说Java类加载机制的,后来想想,JVM的作用是加载编译器编译好的字节码,并解释成机器码,那么首先应该了解字节码,然后再谈加载字节码的类加载机制似乎会好些,所以这篇改成详解字节码。

由于Java纯面向对象的特性,字节码只要能表示一个类的信息,就可以表示整个Java程序了,JVM只要能加载一个类的信息,就能加载整个程序了。所以,不管是字节码,还是JVM加载机制,关注点都是在类。我关注的点主要在于:

1. 由于字节码不是一次性全部加载进入内存,那么JVM是如何知道自己要加载的类信息在.class文件的哪个位置的?

2. 字节码是如何表示类信息的?

3. 字节码会进行程序的优化吗?

第一个问题很简单,因为哪怕一个源文件有很多个类(只有一个public类),编译器也会为其中每个类都生成一个.class文件,JVM加载时按照需要加载的类名称加载即可。

要解决后面的问题,首先我们来看字节码的组成(Mac下用Hex Fiend打开)。

对这样一段代码:

package com.test.main1;

public class ByteCodeTest {

int num1 = 1;

int num2 = 2;

public int getAdd() {

return num1 + num2;

}

}

class Extend extends ByteCodeTest {

public int getSubstract() {

return num1 - num2;

}

}

我们来分析其中的Extend类。

用Hex Fiend打开编译后的.class文件是这样的(16进制代码):

由于class文件没有分隔符,所以每个位置代表什么、各个部分的长度等格式是严格规定死的,见下表:

其中u1、u2、u4、u8代表几个字节的无符号数,在反编译出来的16进制文件中,两个数字代表一个字节,也就是u1。

从头到尾一项一项地看:

(1)magic:u4,魔数,代表本文件是.class文件。.jpg等也会有这种魔数,正因为魔数存在,即使将*.jpg改成*.123,也能照常打开。

(2)minor version、major version:各u2,版本号,向下兼容,即高版本JDK可以使用低版本的.class文件,反之不行。

(3)constant_pool_count:u2,常量池中常量的数量,0019代表有24个。

(4)接下来就是具体的常量,共constant_pool_count-1个。

常量池通常存两种类型的数据:

字面量:如字符串、final修饰的常量等;

符号引用:如类/接口的全限定名、方法的名称和描述、字段的名称和描述等。

根据反编译出来的数字,首先查下表得到该常量的类型和长度,接下来的与查得的长度相等的数字则表示该常量具体的值。

如070002,就表示该种类型为CONSTANT_Class_info,它的tag为u1,且接下来u2长度为index指向全限定名常量项的索引。这个索引还要结合javap -verbose打开的class文件一起看,这里清晰地列出了常量池中的内容和顺序:

在这里可以看到0002索引项的常量为:com/test/main1/Extend,是类的全限定名。如果是值是字符串,那么需要根据该值转换成十进制并查ASCII码表得到具体的字符。接下来的常量都照此分析:

01001563 6F6D2F74 6573742F 6D61696E 312F4578 74656E64:com/test/main1/Extend

070004:com/test/main1/ByteCodeTest

01001B63 6F6D2F74 6573742F 6D61696E 312F4279 7465436F 64655465 7374:com/test/main1/ByteCodeTest

0100063C 696E6974 3E:

01000328 2956:()V

01000443 6F6465:Code

0A000300 09:com/test/main1/ByteCodeTest、"":()V

0C000500 06:、()V

01000F4C 696E654E 756D6265 72546162 6C65:LineNumberTable

0100124C 6F63616C 56617269 61626C65 5461626C 65:LocalVariableTable

01000474 686973:this

0100174C 636F6D2F 74657374 2F6D6169 6E312F45 7874656E 643B:Lcom/test/main1/Extend;

01000C67 65745375 62737472 616374:getSubstract

01000328 2949:()I

09000100 11:com/test/main1/Extend、num1:I

0C001200 13:num1、I

0100046E 756D31:num1

01000149:I

09000100 15:com/test/main1/Extend、num2:I

0C001600 13:num2、I

0100046E 756D32:num2

01000A53 6F757263 6546696C 65:SourceFile

01001142 79746543 6F646554 6573742E 6A617661:ByteCodeTest.java

至此,常量池中的常量全部解析完毕。

(5)再接下来是u2的access_flags:access_flags访问标志的主要目的是标记该类是类还是接口,如果是类,访问权限是否为public,是否是abstract,是否被标志为final等,见下表:

Flag_name

Value

Interpretation

ACC_PUBLIC

0x0001

表示访问权限为public,可以从本包外访问

ACC_FINAL

0x0010

表示由final修饰,不允许有子类

ACC_SUPER

0x0020

较为特殊,表示动态绑定直接父类,见下面的解释

ACC_INTERFACE

0x0200

表示接口,非类

ACC_ABSTRACT

0x0400

表示抽象类,不能实例化

ACC_SYNTHETIC

0x1000

表示由synthetic修饰,不在源代码中出现,见附录[2]

ACC_ANNOTATION

0x2000

表示是annotation类型

ACC_ENUM

0x4000

表示是枚举类型

所以,本类中的access_flags是0020,表示这个Extend类调用父类的方法时,并非是编译时绑定,而是在运行时搜索类层次,找到最近的父类进行调用。这样可以保证调用的结果是一定是调用最近的父类,而不是编译时绑定的父类,保证结果的正确性。这个可以参见文章[1]。

(6)this_class:u2的类索引,用于确定类的全限定名。本类的this_class是0001,表示在常量池中#1索引,是com/test/main1/Extend

(7)super_class:u2的父类索引,用于确定直接父类的全限定名。本类是0003,#3是com/test/main1/ByteCodeTest

(8)interfaces_count:u2,表示当前类实现的接口数量,注意是直接实现的接口数量。本类中是0000,表示没有实现接口。

(9)Interfaces:表示接口的全限定名索引。每个接口u2,共interfaces_count个。本类为空。

(10)fields_count:u2,表示类变量和实例变量总的个数。本类中是0000,无。

(11)fields:fileds的长度为filed_info,filed_info是一个复合结构,组成如下:

filed_info: {

u2        access_flags;

u2        name_index;

u2        descriptor_index;

u2        attributes_count;

attribute_info   attributes[attributes_count];

}

由于本类无类变量和实例变量,故本字段为空。

(12)methods_count:u2,表示方法个数。本类中是0002,表示有2个。

(13)methods:methods的长度为一个method_info结构:

method_info {

u2        access_flags;          0000    ?

u2        name_index;           0005   

u2        descriptor_index;         0006    ()V

u2        attributes_count;         0001    1个

attribute_info   attributes[attributes_count];   0007    Code

}

其中attribute_info结构如下:

attribute_info {

u2  attribute_name_index;  0007  Code

u1  attribute_length;

u1  info[attribute_length];

}

上面

By © 2017 likecs 版权所有.

粤ICP备12038626号-2

Powered By WordPress . Theme by Luju

java 字节码详解_Java基础篇(JVM)——字节码详解相关推荐

  1. java的继承和访问_Java基础篇:如何解决成员的访问和继承?

    Java基础篇:如何解决成员的访问和继承? 尽管子类包括超类的所有成员,它不能访问超类中被声明成private的成员.例如,考虑下面简单的类层次结构: /* In a class hierarchy, ...

  2. 资料搜集-JAVA系统的梳理知识5-JAVA基础篇JVM

    <!-- TOC -->- [Collections 工具类和 Arrays 工具类常见方法](#collections-工具类和-arrays-工具类常见方法)- [Collection ...

  3. java 字节码加载_java面试题jvm字节码的加载与卸载

    虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换分析和初始化,最终形成可以被虚拟节直接使用的JAVA类型,这就是虚拟机的类加载机制. 类从被加载到虚拟机内存到卸载出内存的生命周期 ...

  4. [翻译]拒绝服务***详解之基础篇

    [翻译]拒绝服务***详解之基础篇 本帖被 EvilOctal 从 论坛原创{ Original Paper } 移动到本区(2007-03-19) Constantly 51cto技术博客 Cons ...

  5. Nginx实战基础篇一 源码包编译安装部署web服务器

    Nginx实战基础篇一 源码包编译安装部署web服务器 版权声明: 本文遵循"署名非商业性使用相同方式共享 2.5 中国大陆"协议 您可以自由复制.发行.展览.表演.放映.广播或通 ...

  6. Nginx基础篇-Nginx 源码编译安装与平滑升级

    Nginx基础篇-Nginx 源码编译安装与平滑升级 Nginx官网下载地址 http://nginx.org/ 1.安装依赖包 yum -y install pcre-devel zlib-deve ...

  7. Java生产环境下性能监控与调优详解 第8章 JVM字节码与Java代码层调优

    第8章 JVM字节码与Java代码层调优 8-1 jvm字节码指令-1 8-2 jvm字节码指令-2 8-3 i++与++i 8-4 字符串+拼接 8-5 Try-Finally字节码 8-6 Str ...

  8. java 必须存在默认构造器_Java默认构造方法在字节码的实现

    方法在程序的重要性不言而喻,了解方法在字节码中的表达能够使我们开发做到更加心中有数. 再看class文件结构 上一步已经分析完了class文件中的字段(field_info)的表达,接下来就是方法数( ...

  9. Linux平台Makefile文件的编写基础篇和GCC参数详解

    问:gcc中的-I.是什么意思....看到了有的是gcc -I. -I/usr/xxxxx..那个-I.是什么意思呢 最佳答案 答:-Ixxx 的意思是除了默认的头文件搜索路径(比如/usr/incl ...

最新文章

  1. katalon进行app测试_使用Katalon Studio创建你的第一个API测试
  2. 2021-春季学习-智能车技术创新与实践-Lesson2
  3. oracle lgwr io100%,数据库服务器系统I/O 100%案例分析
  4. sap Bydesign 中解决添加元素或者字段时,多语言翻译的问题
  5. java对象是 什么的集合_java持有对象-集合类
  6. 十九、“文捷笔妙活如水,气定神闲稳若山。”(2021.6.7)
  7. Solr入门和实践以及我对Solr的8点理解
  8. 以持续集成工具实现DevOps之禅
  9. 软件系统换服务器地址,天正软件客户端修改服务器地址
  10. 给即将35岁的产品经理提个醒
  11. 【chorme插件开发】第二节:插件的配置文件说明及素材
  12. 基于c++11新标准开发一个支持多线程高并发的网络库
  13. 语音数据增强算法汇总(附代码)
  14. 计算机教室电气设计规范,车库电气设计规范.docx
  15. reg51 reg52区别
  16. C语言规定 程序中各函数之间_,C语言规定,程序中各函数之间________。 答案:既允许直接递归调用也允许间接递归调用...
  17. [电影]推荐《启示》--完美的玛雅文化背景
  18. Python每日一记192计算机组成原理之存储器存取周期、存储器带宽
  19. java 定义一个方法,用于比较两个int数组的数字是否相同
  20. 终于有人把TCP/IP讲的明明白白了,搞懂真的不难,只需要看这一篇就够了

热门文章

  1. 九城投资贾跃亭,世间悲催莫过于美人迟暮,英雄落寞
  2. 直播、视频会议、屏幕共享—RTC实时音视频各大平台如何选择
  3. 深度揭秘亚马逊无货源运营思路,掌握运营技巧
  4. CoreAnimation图层的树状结构和寄宿图
  5. 初出茅庐的小李第113篇博客项目笔记之机智云智能浇花器实战(2)-基础Demo实现
  6. redis 五种数据类型查询命令
  7. PS CC 2015 修改图片颜色和大小
  8. PS-cs3字体无法响应
  9. arcgisApi加载页面默认引用在线字体
  10. 做期货最有效的交易方法和技巧吗?