精华内容
下载资源
问答
  • Java中基本类型字节

    2019-12-26 22:26:08
    java中基本类型占用字节数 1. 整型 类型 存储需求 bit数 取值范围 备注 int 4字节 4*8 -2147483648~2147483647 即 (-2)的31次方 ~ (2的31次方) - 1。 为什么是31而不是32?因为第一...

    一. java中基本类型占用字节数

    1. 整型

    类型存储需求bit数取值范围备注
    int4字节4*8-2147483648~2147483647即 (-2)的31次方 ~ (2的31次方) - 1。
    为什么是31而不是32?因为第一位是符号位,用来表示正负的
    short2字节2*8-32768~32767 
    long8字节8*8  
    byte1字节1*8-128~127 

    2. 浮点型

    类型存储需求bit数取值范围备注
    float4字节4*8 float类型的数值有一个后缀F(例如:3.14F)
    double8字节8*8 没有后缀F的浮点数值(如3.14)默认为double类型

    3. char类型

    类型存储需求bit数取值范围备注
    char2字节2*8 Java中,只要是字符,不管是数字还是英文还是汉字,都占两个字节。

    至于为什么 Java 中 char 无论中英文数字都占用2字节,是因为 Java 中使用 Unicode 字符,所有字符均以2个字节存储。 而如果需要识别字符是否为中文,可以使用正则匹配式:

    String _regex = "[\\u4e00-\\u9fa5]";

     

    4. boolean类型

    类型存储需求bit数取值范围备注
    boolean1字节1*8false、true 

    二. 为什么java中int占4个字节。

    • int是最基本的类型,一般和CPU的字宽一致。
    • 操作系统16位的时候,int 2字节,操作系统32位的时候,int 4字节,由于32位系统之前占主流地位,实际现在就算是64位系统,出于兼容性考虑,int也是4字节的
    • 一个字节占8位,所以:32/8 = 4个字节

    三. Uint16、Uint32、Uint64、Char(16)的意思

    • Uint16表示规定一个int占16位,16/8=2个字节,所以你需要把int转换成2个字节进行传输,也就是byte[2]。
      • 注意,如果直接用强转的方式,例如(byte)1,这里1是被转成一个字节,一个字节只能表示-128~127。
      • 如果想要把一个int值转成4个字节byte[4],请看另一篇文章: java中byte[ ]和各种数据类型的相互转换
    • Uint32表示规定一个int占32位,32/8=4个字节,所以你需要把int转换成4个字节进行传输,也就是byte[4]。
    • Uint64表示规定一个int占64位,64/8=8个字节,所以你需要把int转换成8个字节进行传输,也就是byte[8]。
    • Char(16)表示传输16个字节。至于一个char要占一个字节还是两个字节,要看具体的协议定制。只要接收和发送方按照相同的规则来解析转化即可。
      • 例如要传输passWord = “abcd”这样一串密码
      • 发送方如果用java的byte b[] = passWord.getBytes(),则b的长度是4位,内容是:61 62 63 64(abcd的ASCII值的16进制) (用getBytes方法的话,一个char一个字节)
      • 接收方只要同样按4个字节来解析即可,例如:
    private String decode(byte[] b) {
      char[] psw = new char[4];
      for (int i = 0; i < psw.length; i++) {
        psw[i] = (char) b[i];
      }
      return String.valueOf(psw);
    }

     

    展开全文
  • 字节数组转字符串(Java

    万次阅读 2020-09-10 16:48:49
    字节数组转字符串(Java) 我们在开发中经常会遇到将字节数组转换成字符串的情况,这里提供一个简单的方法即可实现。 使用String构造方法转换: String res = new String(bytes, "UTF-8") 注意:第二个参数代表了...

    字节数组转字符串(Java)


    我们在开发中经常会遇到将字节数组转换成字符串的情况,这里提供一个简单的方法即可实现。

    使用String构造方法转换:

    String res = new String(bytes, "UTF-8")
    

    注意:第二个参数代表了字符的格式,因为字节流本身是无格式的,但转换成字符后,字符是有各种格式的,比如这里的字符格式是"UTF-8”,如果使用了错误的字符格式,转换后的字符串就会是乱码。

    展开全文
  • 算法相关,密钥 Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象...
  • Java字节

    千次阅读 2019-01-14 13:23:40
    Java最黑科技的玩法就是字节码编程,也就是动态修改或是动态生成 Java 字节码。使用字节码可以玩出很多高级的玩法,最高级的还是在 Java 程序运行时进行字节码修改和代码注入。听起来是不是一些很黑客,也很黑科技的...

    Java最黑科技的玩法就是字节码编程,也就是动态修改或是动态生成 Java 字节码。使用字节码可以玩出很多高级的玩法,最高级的还是在 Java 程序运行时进行字节码修改和代码注入。听起来是不是一些很黑客,也很黑科技的事?是的,这个方式使用 Java 这门静态语言在运行时可以进行各种动态的代码修改,而且可以进行无侵入的编程。
    比如,我们不需要在代码中埋点做统计或监控,可以使用这种技术把我们的监控代码直接以字节码的方式注入到别人的代码中,从而实现对实际程序运行情况进行统计和监控。但是要做到这个事,还需要学习一个叫 Java Agent 的技术(可以参考我的这篇文章:Java Agent)。

    1、Class类文件的结构

    根据 Java 虚拟机规范的规定,Class 文件格式采用一种类似 C 语言结构体的伪结构来存储数据,这种伪结构中只有两种数据类型:无符号数和表
    无符号数属于基本的数据类型,以 u1、u2、u4、u8 来分别代表 1 个字节、2 个字节、4个字节和 8 个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者按照 UTF-8 编码构成字符串值。
    是由多个无符号数或者其他表作为数据项构成的复合数据类型,所有表都习惯性地以“_info”结尾。表用于描述有层次关系的复合结构的数据,整个 Class 文件本质上就是一张表,它由下表所示的数据项构成。

    类型名称数量描述
    u4magic1魔数,占用4个字节,offset 0-3
    u2minor_version1次版本号,offset 4-5
    u2major_version1主版本号 ,offset 7-8
    u2constant_pool_count1常量池数量,offset 8-9
    cp_infoconstant_pollconstant_pool_count-1常量池,Class 文件之中的资源仓库。数量不固定
    u2access_flags1访问标志,用于识别一些类或者接口层次的访问信息
    u2this_class1类索引,用于确定这个类的全限定名
    u2super_class1父类索引,用于确定这个类的父类的全限定名
    u2interfaces_count1接口计数器,表示索引表的容量
    u2interfacesinterfaces_count接口索引集合,用来描述这个类实现了哪些接口
    u2fields_count1字段容量计数器,记录这个表含有多少个字段
    field_infofieldsfields_count字段表集合,用于描述接口或者类中声明的变量
    u2methods_count1方法表计数器,记录这个表含有多少个方法
    method_infomethodsmethods_count方法表集合,存放 Class 的方法集合
    u2attributes_count1属性表计数器,表示字段表或方法表有多少个属性
    attributeattributesattributes_count属性表集合,在 Class 文件、字段表、方法表都可以携带自己的属性表集合,以用于描述某些场景专有的信息

    为方便讲解,在这里准备了一段最简单的代码,也希望大家能跟着实际操作一遍:

    package org.clazz;
    
    public class TestClazz {
        private int m;
    
        public int inc() {
            return m + 1;
        }
    }
    

    使用 javac 将这个文件转换成 Class,然后用十六进制编辑器 WinHex 打开这个 Class 文件:
    在这里插入图片描述
    有了以上的知识准备,现在我们一起分析上面的 Class 分别代表什么意思。揭开这层神秘的面纱!

    1.1、魔数

    每个 Class 文件的头 4 个字节称为魔数(Magic Number),它的唯一作用是确定这个文件是否为一个能被虚拟机接受的 Class 文件。
    很多文件存储标准中都使用魔数来进行身份识别,譬如图片格式,如 gif 或者 jpeg 等在文件头中都存有魔数。
    文件格式的制定者可以自由地选择魔数值,只要这个魔数值还没有被广泛采用过同时又不会引起混淆即可。
    我们看到 TestClazz.class 的魔数也就是头 4 个字节为 CA FE BA BE,用十六进制表示是 0xCAFEBABE(咖啡宝贝?这个名称也太浪漫了吧)。这也意味着每个 Class 文件的魔数值都必须为 0xCAFEBABE。
    在这里插入图片描述

    1.2、Class 文件的版本

    紧接着魔数的 4 个字节存储的是 Class 文件的版本号:5-6 个字节是次版本号(Minor Version),7-8 个字节是主版本号(Major Version)。Java 的版本号是从 45 开始的,JDK 1.1 之后的每个JDK 大版本发布主版本号加 1,高版本的 JDK 能向下兼容以前版本的 Class 文件,但不能运行以后版本的 Class 文件,即使文件格式并未发生任何变化,虚拟机也必须拒绝执行超过起把那本号的 Class 文件。
    Class 文件版本号:

    JDK版本号10进制版本号16进制版本号
    1.145.000 00 00 2D
    1.246.000 00 00 2E
    1.347.000 00 00 2F
    1.448.000 00 00 30
    1.549.000 00 00 31
    1.650.000 00 00 32
    1.751.000 00 00 33
    1.852.000 00 00 34

    再看看文件对应的值:
    在这里插入图片描述
    我们看到代表主版本号的 7-8 个字节的值为 0x0034,也即十进制的 52,该版本号说明这个文件是可以被 JDK 1.8 或以上版本虚拟机执行的 Class 文件。

    1.3、常量池

    紧接着主次版本号之后的是常量池入口,常量池可以理解为 Class 文件之中的资源仓库,它是占用 Class 文件空间最大的数据项目之一。
    由于常量池中常量的数量是不固定的,所以在常量池的入口需要放置一项 u2 类型的数据,代表常量池容量计数值(constant_pool_count)。
    在这里插入图片描述
    如上图所示,常量池容量为十六进制数 0x0016,即十进制的 19,结合上面的 Class 表,我们能知道常量池中有 19 - 1 = 18 项常量。
    常量池容量计数值之后就是常量池,常量池中主要存放两大类常量:字面量(Literal)和符号引用(Symbolic References)。
    字面量比较接近于 Java 语言层面的常量概念,如文本字符串、声明为 final 的常量值等。
    符号引用则属于编译原理方面的概念,包括了下面三类常量:

    • 类和接口的全限定名(Fully Qualified Name)
    • 字段的名称和描述符(Descriptor)
    • 方法的名称和描述符

    常量池中每一项常量都是一个表,总共 14 种表:

    类型标志描述
    CONSTANT_Utf8_info1UTF-8 编码的字符串
    CONSTANT_Integer_info3整型字面量
    CONSTANT_Float_info4浮点型字面量
    CONSTANT_Long5长整型字面量
    CONSTANT_Double_info6双精度浮点型字面量
    CONSTANT_Class_info7类或接口的符号引用
    CONSTANT_String_info8字符串类型字面量
    CONSTANT_Fieldref_info9字段的符号引用
    CONSTANT_Methidref_info10类中方法的符号引用
    CONSTANT_InterfaceMethodref_info11接口中方法的符号引用
    CONSTANT_NameAndType_info12字段或方法的部分符号引用
    CONSTANT_MethodHandle_info15表示方法句柄
    CONSTANT_MethodType_info16标识方法类型
    CONSTANT_InvokeDynamic_info18标识一个动态方法调用点

    之所以说常量池是最烦琐的数据,是因为这 14 中常量类型各自均有自己的结构。
    我们再来看图中常量池的第一项常量,它的标志位(偏移地hi:0x0000000A)是 0x0A,转换为十进制的值为 10,查常量表中对应的标志为 10 的常量属于 CONSTANT_Methodref_info 类型。
    在这里插入图片描述
    我们看一下 CONSTANT_Methodref_info 类型常量的结构:

    名称类型描述
    tagu1值为10
    indexu2指向声明方法的类描述符 CONSTANT_Class_info 的索引项
    indexu2指向名称及类型描述符 CONSTANT_NameAndType 的索引项

    上图中的第一个 index 十六进制为 0x0004,即十进制的 4,表示指向常量池中第 4 个常量。
    第二个 index 十六进制为 0x000F,即十进制的 15,表示指向常量吃中的第 15 个常量。
    (先不管第4、15 常量表示什么)
    上面分析的是第一个常量值,接着分析第二个常量值,它的标志位(地址:0x0000000F)是 0x09,即十进制的 9,表示这个常量属于 CONSTANT_Fieldref_info 类型,此常量代表字段的符号引用。
    在这里插入图片描述
    CONSTANT_Fieldref_info 型常量的结构:

    名称类型描述
    tagu1值为9
    indexu2指向声明字段的类或者接口描述符 CONSTANT_Class_info 的索引项
    indexu2指向字段描述符 CONSTANT_NameAndType 的索引项

    以上分析了 TestClazz.class 常量池中 18 个常量中的前两个,其余的 16 个依次类推:
    在这里插入图片描述
    需要注意的是第 18 个常量,tag 标志为 0x01 表示 CONSTANT_Utf8_info :

    名称类型描述
    tagu1数量 1
    lengthu2长度,表示占用几个字节
    bytesu1占用 length 个字节

    注意 bytes 字段的长度,是根据 length 计算的,length 为 0x0010 转换十进制为 16,所以后面的 bytes 占用 16 个字节。
    最后将 14 中常量项的结构定义总结为下表,供大家参考:
    在这里插入图片描述

    1.4、访问标志

    在常量池结束之后,紧接着的两个字节代表访问标志(access_flags),这个标志用于识别一些类或者接口层次的访问信息,包括:这个 Class 是类还是接口;是否定义为 public 类型;是否定义为 abstract 类型;如果是类的话,是否被声明为 final 等。具体标志位以及标志的含义见下表:

    标志名称标志值含义
    ACC_PUBLIC0x0001是否为 public 类型
    ACC_FINAL0x0010是否被声明为 final,只有类可设置
    ACC_SUPER0x0020是否允许使用 invokespecial 字节码指令的新语意,invokespecial指令的语意在 JDK 1.0.2 发生过改变,为了区别这条指令使用哪种语意,JDK 1.0.2 之后编译出来的类的这个标志都必须为真
    ACC_INTERFACE0x0200标识这是一个接口
    ACC_ABSTRACT0x0400是否为 abstract 类型,对于接口或者抽象类来说,此标志值为真,其他类值为假
    ACC_SYNTHETIC0x1000标识这个类并非由用户代码产生的
    ACC_ANNOTATION0x2000标识这是一个注解
    ACC_ENUM0x4000标识这是一个枚举

    在这里插入图片描述
    TestClazz.class 是一个普通的 java 类,不是接口、枚举,因此它的ACC_PUBLIC、ACC_SUPER标志为真,其他标志为假,因此它的 access_flags 的值为:0x0001|0x0020 = 0x0021。

    1.5、类索引、父类索引与接口索引集合

    类索引(this_class)和父类索引(super_class)都是一个 u2 类型的数据,而接口索引结合(interfaces)是一组 u2 类型的数据的集合,Class 文件中由这三项数据来确定这个类的继承关系。
    类索引和父类索引都是指向一个类型为 CONSTANT_Class_info 的类描述符常量。
    在这里插入图片描述
    图中看到,TestClazz中的类索引指向的是第 3 个常量,父类索引指向的是第 4 个常量。
    对于接口索引集合,入口的第一项——u2 类型的数据为接口计数器(interfaces_count),表示索引表的容量。如果该类没有实现任何接口,则该计数器值为 0 ,后面接口的索引表不再占用任何字节。

    1.6、字段表集合

    字段表用于描述接口或者类中声明的变量。字段(field)包括类级变量以及实例变量,但不包括在方法内部声明的局部变量。
    字段表结构:

    类型名称数量
    u2access_flags1
    u2name_index1
    u2descriptor_index1
    u2attributes_count1
    attribute_infoattributesattributes_count

    字段修饰符放在 access_flags 项目中,它与类中的 access_flags 项目是非常类似的,都是一个 u2 的数据类型,其中可以设置的标志位和含义见表:

    标志名称标志值含义
    ACC_PUBLIC0x0001字段是否为 public
    ACC_PRIVATE0x0002字段是否为 private
    ACC_PROTECTED0x0004字段是否为 proctected
    ACC_STATIC0x0008字段是否为 static
    ACC_FINAL0x0010字段是否为 final
    ACC_VOLATILE0x0040字段是否为 volatile
    ACC_TRANSIENT0x0080字段是否为 transient
    ACC_SYNTHETIC0x1000字段是否由编译器自动产生的
    ACC_ENUM0x4000字段是否为 enum

    跟随 access_flags 标志的是两项索引值:name_index 和 descriptor_index。它们都是对常量池的引用,分别代表着字段的简单名称以及字段和方法的描述符。
    在这里插入图片描述

    1.7、方法表集合

    方法表的内容和字段表几乎采用了完全一致的方式,方法表结构:

    类型名称数量
    u2access_flags1
    u2name_index1
    u2descriptor_index1
    u2attributes_count1
    attribute_infoattributesattributes_count

    access_flags 方法访问标志:

    标志名称标志值含义
    ACC_PUBLIC0x0001方法是否为 public
    ACC_PRIVATE0x0002方法是否为 private
    ACC_PROTECTED0x0004方法是否为 proctected
    ACC_STATIC0x0008方法是否为 static
    ACC_FINAL0x0010方法是否为 final
    ACC_SYNCHRONIZED0x0020方法是否为 synchronized
    ACC_BRIDGE0x0040方法是否是由编译器产生的桥接方法
    ACC_VARARGS0x0080方法是否接受不定参数
    ACC_NATIVE0x0100方法是否为 native
    ACC_ABSTRACT0x0400方法是否为 abstract
    ACC_STRICTFP0x0800方法是否为 strictfp
    ACC_SYNTHETIC0x1000方法是否由编译器自动产生的

    TestClazz对应的位置:
    在这里插入图片描述
    注意,方法表集合只存放了方法名称,索引等,方法里的代码存放在方法属性表集合中一个名为“Code”的属性里面,这就是下面需要将到的属性表集合。

    1.8、属性表集合

    属性表(attribute_info)在 Class 文件、字段表、方法表都可以携带自己的属性表集合,以用于描述某些场景专有的信息。
    与 Class 文件中其他的数据项目要求严格的顺序、长度和内容不同,属性表集合的限制稍微宽松些,不再要求各个属性表具有严格顺序,并且只要不与已有属性名重复,任何人实现的编译器都可以向属性表中写入自己定义的属性信息,Java 虚拟机运行时会忽略掉它不认识的属性。
    虚拟机规范预定义的属性:

    属性名称使用位置含义
    Code方法表Java 代码编译成的字节码指令
    ConstantValue字段表final 关键字定义的常量值
    Deprecated类、方法表、字段表被声明为 deprecated 的方法和字段
    Exceptions方法表方法抛出的异常
    EnclosingMethod类文件仅当一个类为局部类或者匿名类时才能拥有这个属性,这个属性用于标识这个类所在的外围方法
    InnerClasses类文件内部类列表
    LineNumberTableCode 属性Java 源码的行号与字节码指令的对应关系
    LocalVariableTableCode 属性方法的局部变量描述
    StackMapTableCode 属性JDK 1.6 中新增的属性,供新的类型检查验证器(Tyoe Checker)检查和处理目标方法的局部变量和操作数栈所需要的类型是否匹配
    Signature类、方法表、字段表这个属性用于支持泛型情况下的方法签名,在 Java 语言中,任何类、接口、初始化方法或成员的泛型签名如果包含了类型变量(Type Variables)或参数化类型(Parameterized Types),则 Signature 属性会为它记录泛型签名信息。由于 Java 的泛型采用擦除法实现,在为了避免类型信息被擦除后导致签名混乱,需要这个属性记录泛型中的相关信息
    SourceFile类文件记录源文件名称
    SourceDebugExtension类文件JDK 1.6 中新增的属性,SourceDebugExtension 属性用于存储额外的调试信息。譬如在进行 JSP 文件调试时,无法通过 Java 堆栈来定位到 JSP 文件的行号,JSR-45 规范为这些非 Java 语言编写,却需要编异常字节码并运行在 Java 虚拟机中的程序提供了一个进行调试的标准机制,使用 SourceDebugExtension 属性就可以用于存储这个标准所新加入的调试信息
    Synthetic类、方法表、字段表标识方法或字段为编译器自动生成的
    LocalVariableTypeTable它使用特征签名代替描述符,是为了引入泛型语法之后能描述泛型参数化类型而添加
    RuntimeVisibleAnnotations类、方法表、字段表为动态注解提供支持。RuntimeVisibleAnnotations 属性用于指明哪些注解是运行时(实际上运行时就是进行反射调用)可见的
    RuntimeInvisibleAnnotations类、方法表、字段表与 RuntimeVisibaleAnnotations 属性作用刚好相反,用于指明哪些注解是运行时不可见的
    RuntimeVisibleParameterAnnotations方法表作用与 RuntimeVisibleAnnotations 属性类似,只不过作用对象为方法参数
    RuntimeInvisibleParameterAnnotations方法表作用与 RuntimeInvisibleAnnotations 属性类似,只不过作用对象为方法参数
    AnnotationDefault方法表用于记录注解类元素的默认值
    BootstrapMethods类文件JDK 1.7 中新增的属性,用于保存 invokedynamic 指令引用的引导方法限定符

    对于每个属性,它的名称需要从常量池中引用一个 CONSTANT_Utf8_info 类型的常量来表示,而属性值的结构则是完全自定义的,只需要通过一个 u4 的长度属性去说明属性值所占用的位数即可,一个符合规则的属性表应该满足下表所定义的结构。
    属性表结构:

    类型名称数量
    u2attribute_name_index1
    u4attribute_length1
    u1infoattribute_length

    1.8.1、Code 属性

    Java 程序方法体中的代码经过 Javac 编译器处理后,最终变为字节码指令存储在 Code 属性内。
    Code 属性表结构:

    类型名称数量描述
    u2attibute_name_index1属性名称,指向 CONSTANT_Utf8_info 型常量的索引,常量值固定为“Code”
    u4attribute_length1属性值长度,由于属性名称索引与属性长度一共为 6 字节,所以属性值的长度固定为整个属性表长度减去 6 个字节
    u2max_stack1操作数栈深度最大值,在方法执行的任意时刻,操作数栈都不会超过这个深度。虚拟机运行的时候需要根据这个值来分配栈帧中的操作栈深度
    u2max_locals1局部变量表所需的存储空间,max_locals 的单位是 Slot,Slot 是虚拟机为局部变量分配内存所使用的最小单位
    u4code_length1字节码长度
    u1codecode_length字节码指令字节流,用于存储字节码指令的一系列字节流。文章的末尾会给出“虚拟机字节码指令表”。
    u2exception_table_length1
    exception_infoexception_tableexception_table_length
    u2attributes_count1
    attribute_infoattributesattributes_count

    Code 属性是 Class 文件中最重要的一个属性,如果把一个 Java 程序中的信息分为代码(java代码)和元数据(类、字段、方法定义及其他信息)两部分,那么在整个 Class 文件中,Code 属性用于描述代码,所有其他数据项目都用于描述元数据。
    继续以 TestClazz.class 文件为例
    在这里插入图片描述
    它的操作数栈的最大深度和本地变量表的容量都为 0x0001,字节码区域所占空间的长度为 0x0005。
    虚拟机读取到字节码长度后,按照顺序依次读入紧随的 5 个字节,并根据字节码指令表翻译出所对应的字节码指令。
    翻译 “2A B7 00 0A B1” 的过程:
    1.读入 2A,查表得 0x2A 对应得指令为 aload_0,这个指令得含义是将第 0 个 Slot 中为 reference 类型得本地变量推送到操作数栈顶。
    2.读入 B7,查表得 0xB7 对应得指令为 invokespecial,这条指令的作用是以栈顶的 reference 类型的数据所指向的对象作为方法接收者,调用此对象的实例构造器方法、private 方法或者它的父类的方法。
    3.读入 00 0A,这是 invokespecial 的参数,查常量池得 0x000A 对应的常量为实例构造器“”方法的符号引用。
    4.读入 B1,查表得 0xB1 对应得指令为 return,含义是返回此方法,这条指令执行后,当前方法结束。
    属性表集合除了 Code 属性,还有 Exceptions 属性、LineNumberTable 属性等等,这里就不一一介绍了。有兴趣得童鞋可以自行了解。

    2、javap 工具分析 Class

    在 JDK 的 bin 目录中,Oracle 公司已经为我们准备好一个专门用于分析 Class 文件字节码的工具:javap
    使用命令:

    javap -verbose TestClazz.class
    

    代码清单:

     Last modified 2019-1-14; size 285 bytes
      MD5 checksum c434da45f0fff84f21348a725448f2f5
      Compiled from "TestClazz.java"
    public class org.clazz.TestClazz
      minor version: 0
      major version: 52
      flags: ACC_PUBLIC, ACC_SUPER
    Constant pool:
       #1 = Methodref          #4.#15         // java/lang/Object."<init>":()V
       #2 = Fieldref           #3.#16         // org/clazz/TestClazz.m:I
       #3 = Class              #17            // org/clazz/TestClazz
       #4 = Class              #18            // java/lang/Object
       #5 = Utf8               m
       #6 = Utf8               I
       #7 = Utf8               <init>
       #8 = Utf8               ()V
       #9 = Utf8               Code
      #10 = Utf8               LineNumberTable
      #11 = Utf8               inc
      #12 = Utf8               ()I
      #13 = Utf8               SourceFile
      #14 = Utf8               TestClazz.java
      #15 = NameAndType        #7:#8          // "<init>":()V
      #16 = NameAndType        #5:#6          // m:I
      #17 = Utf8               org/clazz/TestClazz
      #18 = Utf8               java/lang/Object
    {
      public org.clazz.TestClazz();
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
          stack=1, locals=1, args_size=1
             0: aload_0
             1: invokespecial #1                  // Method java/lang/Object."<init>":()V
             4: return
          LineNumberTable:
            line 3: 0
    
      public int inc();
        descriptor: ()I
        flags: ACC_PUBLIC
        Code:
          stack=2, locals=1, args_size=1
             0: aload_0
             1: getfield      #2                  // Field m:I
             4: iconst_1
             5: iadd
             6: ireturn
          LineNumberTable:
            line 7: 0
    }
    SourceFile: "TestClazz.java"
    

    结束

    到此,相信大家能对字节码有一个较深的认识,Java 语言中的各种变量、关键字和运算符号的语义最终都是由多条字节码命令组合而成的,因此字节码命令所能提供的语义描述能力肯定会比 Java 语言本身更强大。

    附录

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • 关于Java字节

    千次阅读 2018-09-24 10:25:23
    关于Java字节码 概述 从写Java文件到编译成字节码文件(也就是.class文件)的过程也就是Java文件编译的过程,我们所写的是Java文件而Java虚拟机编译的是字节码文件 class文件格式 ...

    关于Java字节码

    1. 概述

    从写Java文件到编译成字节码文件(也就是.class文件)的过程也就是Java文件编译的过程,我们所写的是Java文件而Java虚拟机编译的是字节码文件

    2. class文件格式

    class文件格式

    3. 举个栗子来说明一下

    ①先写一个.java文件
    

    Demo的java文件

    ②打开.class文件
    

    Demo的class文件

    3.1 magic 魔数

    前四个字节为魔数,值为:0xCAFE BABE Java创始人 James Gosling制定 用来表示是class 文件 有人会问为什么为cafebaby,联想一下java的咖啡杯图标就知道了。

    3.2 minor_version & major_version 版本号

    minor_version & major_version对应 的16进制为 0000 0034 前两个字节为minor_version 为此版本号 后两个字节为主版本号。所有该文件的版本号为1.8。

    版本号JDK版本号
    2eJDK1.2
    2fJDK1.3
    30JDK1.4
    31JDK1.5
    32JDK1.6
    33JDK1.7
    34JDK1.8

    3.3 常量池

    在版本号之后的为常量池,常量池可以理解为Class文件中的资源仓库。他是Class文件结构中与其他项目关联最多的数据类型,也是占用Class文件空间最大的数据项之一,同时它还是在Class文件中第一个出现的表类型数据项目。由于常量池中的常量的数量是不固定的,所以在常量池的入口需要放置一项u2类型的数据,代表常量池容量计数值(constant_pool_count),这个计数是从1开始而不是从0开始的
    常量池主要存放两大类字面量和符号引用,字面量如文本字符串,声明为final的常量值等,符号引用属于编译原理方面的概念包括三种常量:①类和接口的权限定名 ②字段的名称和描述符 ③方法名和描述符
    常量池每一项常量都是一个表,jdk1.7之前有11种结构不同的表结构数据,在jdk1.7中又增加了三种下图为14种常量类型所代表的具体含义
    常量所代表的具体含义

    在魔数和版本号后面为常量池,0x0016 为常量池容量,十进制为22,这就代表了常量池中有21项常量,索引值范围为1~~21。在Class 文件格式规范制定的时候,设计者将第0项常量空出来是有特殊考虑的,这样做的目的在于满足后面某些指向常量池的索引值的数据在特定情况下需要表达“不引用任何常量池项目的含义”这种情况就可以吧索引置为0来表示。
    0x07查表的标志列可以知道这个常量属于CONSTANT_Class_info类型 此类型代表一个类或者接口的符号引用。
    CONSTANT_Class_info类型比较简单具体结构看下图:
    CONSTANT_Class_info的结构
    tag是标志位,它用于区分常量类型。name_index 是一个索引值 在这里值为0x0002 也即是指向了常量池里的第二个常量
    0x01为常量池中的第二个常量根据标志列可知这个常量为CONSTANT_Utf8_info类型的常量,下图为常量结构

    CONSTANT_Utf8_info常量的结构
    length值说明了这个utf-8编码的字符串长度是多少字节,在这里为0x013表示19个字节,他后面紧跟着的长度为length字节的连续数据是一个使用utf-8缩略编码表示的字符串。
    636f~~~6f 19个字节表示的是使用utf-8缩略编码表示的字符串。翻译完为:com/baidu/test/demo
    我们现在已经分析了两个常量,后续的19个都可以这样分析完成但是Oracle公司给我们提供了一个专门用于分析class文件字节码的工具:Javap 具体如下图
    通过javap解析出的常量池
    从图中可知计算机已经帮我们吧整个常量池都计算了出来。

    3.4 access_flage 访问标志

    在常量池结束后,紧接着的两个字节代表访问标志 access_flags,这个标志用于识别一些类或者接口层测的访问信息,比如:是类还是接口,是否定义为public,是否定义为abstract类型,如果是类的话是否被声明为final等等下面是具体的含义表

    访问标准的具体含义表
    在这里具体值为0x0021 0x0021为0x0021和0x0001的与运算结果,为啥要进行与运算呢,因为access_flags 中共有16个标志位可以使用,当前只定义了8个,没有使用到的标志要求为0,Demo是一个普通java类,不是接口、枚举、或者注解,只有public关键字修饰

    3.5 this_class & super_class &interaces 类索引、父类索引与接口索引集合

    this_class(类索引)、super_class(父类索引)都是一个u2类型的数据,而interfaces(接口索引集合)是一组u2类型的数据的集合class文件由这三个数据来确定这个类的继承关系
    Demo的class文件
    0x0001、0x0003、0x0000 分别表示类索引为1 、父类索引为3、接口索引集合大小为0
    通过前面用javap算出来的常量池可以知道
    类索引为:com/baidu/test/Demo;
    父类索引为: java/lang/Object;

    3.6 field_info字段表集合

    字段表用于描述接口或者类中声明的变量,但是不包括在方法内部声明的局部变量。可以包括的信息有:public、private、protected、static、final、volatile、transient、基本类型、对象、数组、字段名称
    下图为字段表的格式
    字段表结构
    字段访问标注如下图
    字段访问标志
    Demo的class文件
    0x0001 为fields_count
    0x0002 为access_flags
    0x0005 为name_index
    0x0006 为descriptor_index

    3.7 methods 方法表集合

    方法表集合与字段表集合的结构完全一致,结构如下
    在这里插入图片描述
    在访问标志和属性集合的可选项中有所不同,下图为方法访问标志
    在这里插入图片描述
    有人会提出疑问,不知道方法中的代码去哪里了,方法中的Java代码经过编译器编译成字节码指令后存放到方法属性表的一个名为code的属性中了,在下面属性表会进行讲解在这里插入图片描述
    0x0002:methods_count
    0x0001:access_flags
    0x0007:descriptor_index
    0x0008:attribute_count
    0x0009:name_index

    3.8attribute_info属性表集合

    为了能正确解析 class文件,《Java虚拟机规范(第二版)》中预定了9项虚拟机实现应当能识别的属性,而在最新的《java虚拟机规范(java SE 7)》版本中,预定义属性已经增加到了21项,见下图。

    虚拟机规范预定义的属性
    接下来对其中一些关键字段进行讲解
    (1).code
    Java程序方法体中的代码经过javac编译器处理之后,最终变为字节码指令存在code属性内。code属性表结构如下:
    code属性表结构
    attribute_name_index : 是项指向CONSTANT_Utf8_info 型常量的索引,常量值固定为“code”,他代表该属性的名称;
    attribute_length:指示了属性的长度,由于属性名称索引与属性长度一共为6个字节,所以属性值的长度固定为整个属性表长度减去6个字节。
    max_stack 代表了操作数栈深度的最大值,虚拟机运行的时候需要根据这个值来分配栈帧中的操作栈深度。
    max_locals:代表了局部变量表所需的存储空间。
    code_length:和code用来存储java源程序编译后生成的字节码指令。code_length 表示字节码的长度,code是用于存储字节码指令的一系列字节流。
    code 属性是class文件中最重要的一个属性,如果把java程序中的信息分为代码和元数据两部分,那么在整个class文件中,code属性用于描述代码(方法体内的),所有的其他数据项目都用于描述元数据。
    (2). exceptions属性
    exception属性的作用列举方法中可能抛出的受查异常的(Checked Exceptions)也就是方法描述时在throws关键字后面列举的异常。它的结构见下表
    exceptions属性表结构
    (3).LineNumberTable 属性
    LineNumberTable 属性用于描述java源代码行号与字节码行号之间的对应关系。属性表结构如下。
    在这里插入图片描述
    (4).LocalVariableTable属性
    LocalVariableTable属性用于描述栈帧中局部变量表中的变量与java源码中定义的变量之间的关系。属性表结构见下图。
    LocalVariableTable属性表结构
    (6).SourceFile属性
    SourceFile属性用于记录生成这个class文件的源码文件名称。结构见下图。
    SourceFile属性表结构
    (6).ConstantValue属性
    ConstantValue属性的作用是通知虚拟机自动为静态变量赋值。只有被static修饰的变量才能使用这个属性。结构见下图。
    ContantValue属性表结构
    (7).InnerClasses属性
    InnerClasses这个属性会在虚拟机类加载的字节码验证阶段被新类型检查验证其使用。结构见下表
    InnerClasses属性表结构
    (8).Depercated & Synthetic
    Depercated & Synthetic 两个属性的属于标志类型的布尔属性,只存在有和没有的区别,没有属性值的概念。结构加下图
    Depercated & Synthetic属性结构

    4总结

    class文件是java虚拟机执行引擎的数据入口,也是java技术体系的基础构成之一,了解class文件的结构对进一步了解虚拟机执行引擎有很重要的意义。

    展开全文
  • Java知识体系最强总结(2021版)

    万次阅读 多人点赞 2019-12-18 10:09:56
    本人从事Java开发已多年,平时有记录问题解决方案和总结知识点的习惯,整理了一些有关Java的知识体系,这不是最终版,会不定期的更新。也算是记录自己在从事编程工作的成长足迹,通过博客可以促进博主与阅读者的共同...
  • Java基础知识面试题(2020最新版)

    万次阅读 多人点赞 2020-02-19 12:11:27
    原理是什么Java语言有哪些特点什么是字节码?采用字节码的最大好处是什么什么是Java程序的主类?应用程序和小程序的主类有何不同?Java应用程序与小程序之间有那些差别?Java和C++的区别Oracle JDK 和 OpenJDK 的...
  • Java字节码研究

    千次阅读 2019-03-05 18:46:45
    关于怎么查看字节码的五种方法参考本人另一篇文章《Java以及IDEA下查看字节码的五种方法》 1.String和常连池 先上代码: public class TestApp { public static void main(String[] args) { String s1 = ...
  • 从一个class文件深入理解Java字节码结构

    万次阅读 多人点赞 2018-05-15 10:01:56
    我们都知道,Java程序最终是转换成class文件执行在虚拟机上的,那么class文件是个怎样的结构,虚拟机又是如何处理去执行class文件里面的内容呢,这篇文章带你深入理解Java字节码中的结构。 1.Demo源码 首先,...
  • 主要介绍了浅谈java中字节与字符的区别,字节是java中的基本数据类型,用来申明字节型的变量;字符是语义上的单位,它是有编码的,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,...
  • JVM 字节码指令手册 - 查看 Java 字节

    千次阅读 多人点赞 2019-08-15 21:26:27
    JVM 字节码指令手册 - 查看 Java 字节码 jdk 进行的编译生成的 .class 是 16 进制数据文件,不利于学习分析。通过下命令 javap -c Demo.class > Demo.txt 或者其他方式可反汇编,得到字节码文件 一、JVM 指令...
  • Java字节转换为比特位及相关

    千次阅读 2019-11-06 21:52:06
    文章目录字节转换为比特位字串直接上代码:测试:说明:字节(byte)、比特位、整型(int)原码、反码和补码移位运算符>> 有符号,右移>>> 无符号,右移 字节转换为比特位字串 直接上代码: public ...
  • 读懂Java字节

    千次阅读 2018-08-07 23:58:18
    字节码文件信息 常量池 方法表集合 二、分析try-catch-finally的demo 计算机只认识0和1。这意味着任何语言编写的程序最终都需要经过编译器编译成机器码才能被计算机执行。所以,我们所编写的程序在不同的平台上...
  • JAVA八种基本数据类型-字节数和取值范围Java8种基本数据类型: 类型 字节 位数 取值范围 默认值 包装类 boolean 1/8 1 true, false false Boolean byte 1 8 -128-127 0 Byte short 2 16 -...
  • 我们知道在java中一个整型是占用四个字节32位的,而一 个byte类型占用一个字节8位的。所以我们可以用一个整型来最多表示一个长度为4的byte数组,同样我们可以用一个长度为4的byte数组来表示一个整型。下面我们就 ...
  • 1、javap查看字节码内容上文介绍了字节码的结构,本文主要通过一个简单的例子说明class字节码的每一个字段。package com.zcm.test; import java.io.Serializable; public class SourceTest implements ...
  • java基本类型 1.1 java的基本类型 1.整型: byte (1字节), short (2字节)...3.字节型: char (2字节) 4.布尔型:boolean(2字节) 1.2字节定义 字节表示指一小组相邻的二进制数码,是计算机重要的数据单...
  • Java 字节流转化为文件

    千次阅读 2012-02-17 15:46:20
    已知:byte[] bytes=new FileToBytes().TurnBytes(); String btt=bytes.toString(); 上面是别人给的,转化为数组类型的二进制文件流。...下面我要实现的是,把二进制码转化为文件存储到指定的目录,代码实现如下:...
  • 要理解java字节码的运行情况,首先要了解有关JVM的一些知识,这些是java字节码运行的先决条件。 JVM数据类型 Java是静态类型的,它会影响字节码指令的设计,这样指令就会期望自己对特定类型的值进行操作...
  • Java字节码指令简介

    千次阅读 2016-06-04 12:02:30
    本文是《深入理解Java虚拟机》中第六章的...Java虚拟机的指令由两部分组成,首先是一个字节长度、代表某种含义的数字(即操作码),在操作码后面跟着零个或多个代表这个操作所需的参数(即操作数)。由于Java虚拟机采用
  • java字节数组流操作

    千次阅读 2017-09-07 12:00:15
    需求先给一个需求,给一个字节数组,然后往这个数组中放入各种数据,比如整形,浮点,字符串等。java内置类java提供了两个流来操作数组,ByteArrayOutputStream和ByteArrayInputStream。然后使用DataOutputStream...
  • 字节跳动Java实习面试题目大全

    千次阅读 多人点赞 2019-07-16 17:07:20
    字节跳动的邮件会说考察通用的业务问题和过往的项目经历 字节跳动一定会考算法题,建议有针对性的刷LeetCode探索里面的字节跳动算法题专场,里面的算法题真的很准,我面试时就碰到两题原题。 自我介绍,公司...
  • java程序员是幸福,因为相对于C/C++的不跨平台,JVM为我们屏蔽了大量的底层细节和复杂性,让我们能够将精力放在实现特定的业务逻辑上,所以使用java开发项目效率是比较高的。...无意中看到了字节序,以前竟然...
  • Java字节码结构剖析一:常量池

    千次阅读 2018-10-14 15:01:42
    这篇博客开始,我打算手把手的带大家去解读一下JVM平台下的字节码文件(熟悉而又陌生的感觉)。众所周知,Class文件包含了我们定义的类或接口的信息。然后字节码又会被JVM加载到内存中,供JVM使用。那么,类信息到了...
  • Java语言特点

    万次阅读 多人点赞 2019-06-30 19:37:45
    Java语言是简单的 Java语言的语法与C语言和C++语言很接近,从某种意义上讲,它是由C和C++演变而来,使得大多数程序员很容易学习和使用。 对C++来说进行了简化和一定的提高,如:使用接口代替了复杂的多重继承以及...
  • Java虚拟机采用基于栈的架构,其指令由操作码和操作数组成。 操作码:一个字节长度(0~255),意味着指令集的操作码个数不能操作256条。 操作数:一条指令可以有零或者多个操作数,且操作数可以是1个或者多个字节。...
  • 下面小编就为大家带来一篇基于java中byte数组与int类型的转换(两种方法)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • Java 字节输入流的一些方法

    千次阅读 2017-08-21 21:51:55
    字节输入流的一些方法。。。。
  • Java 字节码指令是 JVM 体系中非常难啃的一块硬骨头,我估计有些读者会有这样的疑惑,“Java 字节码难学吗?我能不能学会啊?” 讲良心话,不是我谦虚,一开始学 Java 字节码和 Java 虚拟机方面的知识我也感觉头大!...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 195,822
精华内容 78,328
关键字:

java字节型

java 订阅