Java字节码(.class文件)格式详解(三)

简介:

2.11 ClassFilemethod_infofield_info中同时存在的Attribute

2.11.1     Synthetic Attribute

Synthetic Attribute用于指示当前类、接口、方法或字段由编译器生成,而不在源代码中存在(不包含类初始函数和实例初始函数)。相同的功能还有一种方式就是在类、接口、方法或字段的访问权限中设置ACC_SYNTHETIC标记。

 

Synthetic AttributeJDK1.1中引入,以支持内嵌类和接口(nested classes and interfaces)。但是以我现在所知,这些功能都是可以通过ACC_SYNTHETIC标记来表达的,为什么还需要存在Synthetic Attribute呢?在什么样的情况下会生成Synthetic Attribute项呢?我还没有找到,需要继续研究。

Synthetic Attribute

type

descriptor

remark

u2

attribute_name_index

constant_pool中的索引,CONSTANT_Utf8_info类型。指定Attribute名称(“Synthetic”)

u4

attribute_length

Attribute内容的字节长度(0)。

 

2.11.2     Signature Attribute

Signature Attribute

type

descriptor

remark

u2

attribute_name_index

constant_pool中的索引,CONSTANT_Utf8_info类型。指定Attribute名称(“Signature”)

u4

attribute_length

Attribute内容的字节长度(2)。

u2

signature_index

constant_pool中的索引,CONSTANT_Utf8_info类型。记录当前类型的签名(类签名、字段签名、方法签名)。

JVM规范中没有指定什么情况下需要生成Signature Attribute。但是从Signature的目的是用于泛型类型,可以推测Signature Attribute存在于当前Signature Attribute所在类型是泛型(泛型类、泛型方法、泛型字段)的时候。它和field_infomethod_infothis_class一起对应于局部变量中的LocalVariableTable AttributeLocalVariableTypeTable Attribute,他们同时都有descriptor版本和signature版本。

 

2.11.3     Deprecated Attribute

Deprecated Attribute指示当前类、方法、字段已经过时了,一些工具,如编译器可以根据该Attribute提示用户他们使用的类、方法、字段已经过时了,最好使用最新版本的类、方法、字段。

Deprecated Attribute

type

descriptor

remark

u2

attribute_name_index

constant_pool中的索引,CONSTANT_Utf8_info类型。指定Attribute名称(“Deprecated”)

u4

attribute_length

Attribute内容的字节长度(0)。

 

2.11.4     RuntimeVisibleAnnotations Attribute

RuntimeVisibleAnnotations Attribute记录了当前类、方法、字段在源代码中定义的、在运行时可见的AnnotationJava程序可以通过反射函数获取这些Annotation。一个attributes集合中只能包含一项RuntimeVisibleAnnotations Attribute,记录所有运行时可见的Annotation

RuntimeVisibleAnnotations Attribute

type

descriptor

remark

u2

attribute_name_index

constant_pool中的索引,CONSTANT_Utf8_info类型。指定Attribute名称(“RuntimeVisibleAnnotations”)

u4

attribute_length

Attribute内容的字节长度。

u2

num_annotations

annotations集合长度。

annotation

annotations[num_annotations]

记录所有运行时可见的annotation的集合。annotation类型详见附录E

 

2.11.5     RuntimeInvisibleParameterAnotations Attribute

RuntimeInvisibleAnnotations Attribute记录了当前类、方法、字段在源代码中定义的、在运行时不可见的Annotation。默认情况下,这些Annotation是不可被Java提供的反射函数获取的,需要通过和实现相关的机制来获取这些Annotation。一个attributes集合中只能包含一项RuntimeInvisibleAnnotations Attribute,记录所有运行时不可见的Annotation

RuntimeInvisibleAnnotations Attribute

type

descriptor

remark

u2

attribute_name_index

constant_pool中的索引,CONSTANT_Utf8_info类型。指定Attribute名称(“RuntimeInvisibleAnnotations”)

u4

attribute_length

Attribute内容的字节长度。

u2

num_annotations

annotations集合长度。

annotation

annotations[num_annotations]

记录所有运行时不可见的annotation的集合。annotation类型详见附录E

 


 

总体格式

magic(0xCAFEBABE)

version(major.minor)

constant pool

CONSTANT_Utf8_info(1)

CONSTANT_Integer_info(3)

CONSTANT_Float_info(4)

CONSTANT_Long_info(5)

CONSTANT_Double_info(6)

CONSTANT_Class_info(7)

CONSTANT_String_info(8)

CONSTANT_Fieldref_info(9)

CONSTANT_Methodref_info(10)

CONSTANT_InterfaceMethodref_info(11)

CONSTANT_NameAndType_info(12)

access_flags

this_class

super_class

interfaces

fields

access_flags

name

descriptor

attributes

ConstantValue Attribute

Synthetic Attribute

Signature Attribute

Deprecated Attribute

RuntimeVisibleAnnotations Attribute

RuntimeInvisibleAnnotations Attribute

methods

access_flags

name

descriptor

attributes

Code Attribute

StackMapTable Attribute

LineNumberTable Attribute

LocalVariableTable Attribute

LocalVariableTypeTable Attribute

Exceptions Attribute

RuntimeVisibleParameterAnnotations Attribute

RuntimeInvisibleParameterAnnotations Attribute

AnnotationDefault Attribute

Synthetic Attribute

Signature Attribute

Deprecated Attribute

RuntimeVisibleAnnotations Attribute

RuntimeInvisibleAnnotations Attribute

attributes

InnerClasses Attribute

EnclosingMethod Attribute

SourceFile Attribute

SourceDebugExtension Attribute

Synthetic Attribute

Signature Attribute

Deprecated Attribute

RuntimeVisibleAnnotations Attribute

RuntimeInvisibleAnnotations Attribute


 

附件Java字节码中的类和接口名

 

Java字节码中类和接口名主要表现以下几点:

1.       类和接口名都是以全限定名的方式存放(包名加类或接口名)。

2.       在源代码中的点分隔符”.”在字节码中以斜杠”/”代替。如:“java.lang.Object-> java/lang/Object

3.       数组类型名做了特殊处理。如:“int[][]-> [[I”、“Thread[]->[Ljava/lang/Thread”。详见附录BJava字节码中的数组类型名

 

 

附件 Java字节码中的数组类型名

 

Java中,数组被认为是类,因而它也有对应的类名表示,而Java字节码为数组名指定了特定的格式:

1. 所有数组名都以“[”开头n维数组有n个“[”。

2. 对引用类型的数组,在“[”后加“L后加引用类型的全限定名。

3. 对基本类型,在“[”后加基本类型的对应字符

基本类型对应字符表

基本类型

对应字符

byte

B

char

C

double

D

float

F

int

I

long

J

short

S

boolean

Z

 

附件 描述符(Descriptor

 

描述符(Descriptor)定义了字段或方法的类型(descriptor is a string representing the type of a field or method.这段描述感觉不怎么精确)。它存放在constant pool中的CONSTANT_Utf8_info类型项中。

 

1.       字段描述符(Field Descriptor

字段描述符是定义了字段、局部变量、参数等类型的字符串。即附录A中的类或接口名。

语法定义:

FieldDescrptor :

FieldType

 

BaseType  BCDFIJSZ(参考附录B中的基本类型对应字符表)

ObjectType  LfullClassName;

ArrayType  [+BaseType | [+ObjectType

FieldType  BaseType | ObjectType | ArrayType

如:[[D -> double[][][Ljava/lang/Thread; -> Thread[]I->intLjava/lang/Object; -> Object

 

2.       方法描述符(Method Descriptor

方法描述符是定义了方法参数、方法返回等信息的字符串。

语法定义:

MethodDescriptor:

         ParameterDescriptor*ReturnDescriptor

 

ParameterDescriptor  FieldType

ReturnDescriptor  FieldType | VoidDescriptor

VoidDescriptor  V

如:void methodint i, Object obj-> (ILjava/lang/Object;)V

Object getValue()-> ( )Ljava/lang/Object;

Object mymethod(int i, double d, Object o) -> (IDLjava/lang/Object;)Ljava/lang/Object;

 

附件 签名(Signature

 

签名(Signature)定义了类、字段或方法的泛型类型信息(signature is a string representing the generic type of a field or method, or generic type information for a class declaration. 这段描述感觉不怎么精确)。它也存放在constant pool中的CONSTANT_Utf8_info类型项中。

它存在于Signature Attribute中,只有包含泛型的类、字段、方法才会产生Signature Attribute

 

签名信息并不是给JVM用的,而是用于编译、调试、反射。

 

1.       类签名

语法定义:

ClassSignature:

FormalTypeParametersopt SuperclassSignature SuperinterfaceSignature*

 

FormalTypeParameters:

<FormalTypeParameter+>

FormalTypeParameter:

Identifier ClassBound InterfaceBound*

ClassBound:

FieldTypeSignatureopt

InterfaceBound:

FieldTypeSignature

SuperclassSignature:

ClassTypeSignature

SuperinterfaceSignature:

ClassTypeSignature

FieldTypeSignature:

ClassTypeSignature

ArrayTypeSignature

TypeVariableSignature

ClassTypeSignature:

PackageSpecifier* SimpleClassTypeSignature

ClassTypeSignatureSuffix* ;

PackageSpecifier:

Identifier / PackageSpecifier*

SimpleClassTypeSignature:

Identifier TypeArgumentsopt

ClassTypeSignatureSuffix:

SimpleClassTypeSignature

TypeVariableSignature:

T Identifier ;

TypeArguments:

<TypeArgument+>

TypeArgument:

WildcardIndicatoropt FieldTypeSignature

*

WildcardIndicator:

+

-

ArrayTypeSignature:

[TypeSignature

TypeSignature:

FieldTypeSignature

BaseType

以上定义没有看懂??例子如:

class MyClass<T> { } 定义的类,产生如下的签名:

<T:Ljava/lang/Object;>Ljava/lang/Object;

而对以下类定义:

class MyClass<T1, T2> extends ClassFileParser implements IndexParser {

}

则产生如下签名:

<T1:Ljava/lang/Object;T2:Ljava/lang/Object;>Lorg/levin/classfilereader/ClassFileParser;Lorg/levin/classfilereader/IndexParser;

 

2.       字段签名

语法定义如上,没能看懂。从Tomcat代码中的Digester.class文件中可以解析得到如下的例子:

Ljava/util/HashMap<Ljava/lang/String;Ljava/util/Stack<Ljava/lang/String;>;>;(对应的descriptor:“Ljava/util/HashMap;”)

Ljava/util/Stack<Ljava/lang/Object;>;(对应的descriptor:“Ljava/util/Stack;”)

 

3.       方法签名

语法定义:

MethodTypeSignature:

FormalTypeParametersopt (TypeSignature*ReturnType

ThrowsSignature*

ReturnType:

TypeSignature

VoidDescriptor

ThrowsSignature:

^ClassTypeSignature

^TypeVariableSignature

也没能看懂。同样从Tomcat代码中的Digester.class文件中可以解析得到如下例子:

(Ljava/lang/String;Ljava/lang/Class<*>;Ljava/lang/String;)V(对应descriptor:“(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;)V”)

(Ljava/lang/String;Ljava/lang/Class<*>;Ljava/lang/String;Z)V(对应descriptor:“(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Z)V”)

()Ljava/util/Map<Ljava/lang/String;Ljava/net/URL;>;(对应descriptor:“()Ljava/util/Map;”)

 

附录Eannotation结构和element_value结构

 

1.      annotation结构

每一项annotation结构记录一项用户定义的annotation的值。如:

    @Test(id = 4, description = "description", useCase = @UseCase())

    @UseCase()

    void testExecute(int a) {

    }

编译器会为该方法生成两项annotation。每项annotation指定了annotation的类型和键值对。

annotation结构

type

descriptor

remark

u2

type_index

constant_pool中的索引。CONSTANT_Utf8_info类型。以字段描述符(field descriptor)方式记录当前结构表示的annotation类型。

u2

num_element_value_pairs

记录当前annotation中的键值对数。

element_value_pair

记录每项annotation中的键值对表。

u2

element_name_index

constant_pool中的索引。CONSTANT_Utf8_info类型。记录当前annotation中当前键值对的键名。如上例的“id”、“description”等。

element_value

value

当前annotation中当前键值对的值。详见element_value结构一节。

element_value_pairs[num_element_value_pairs]

 

 

2.      element_value结构

element_value结构记录了所有annotation类型的键值对中的值。它是一个联合类型,可以表示多种类型的值。

element_value结构

type

descriptor

remark

u1

tag

tag记录了当前annotation键值对中值的类型,’B’’C’’D’’F’’I’’J’’S’’Z’表示基本类型(见附录B中的基本类型对应表);其他的合法值有:

’s’ -> String

‘e’ -> enum constant

‘c’ -> class

‘@’ -> annotation type

‘[‘ -> array

value 联合体类型(union

union类型,记录当前annotaion键值对中的值。

u2

constant_value_index

constant_pool中的索引,索引项必须是常量类型。当tag中的值为’B’ ‘C’ ‘D’ ‘F’ ‘I’ ‘J’ ‘S’ ‘Z’ ‘s’时该项有效。

enum_const_value

tag值为’e’时,该项有效。记录枚举类型值。

u2

type_name_index

constant_pool中的索引,CONSTANT_Utf8_info类型。记录当前枚举类型二进制名(binary name,好像就是类型名,以descriptor的形式表示)。

u2

const_name_index

constant_pool中的索引,CONSTANT_Utf8_info类型。记录当前枚举类型的值(枚举类型内部成员字符串)。

enum_const_value

u2

class_info_index

constant_pool中的索引,CONSTANT_Utf8_info类型。以descriptor记录当前值所表达的Class类型。当tag值为’c’时,该项有效。

annotation

annotation_value

tag值为’@’时,该项有效。记录当前annotation键值对中的值为内嵌的annotation

array_value

tag值为’[‘时,该项有效。记录当前annotation键值对中的值为数组类型。

u2

num_values

数组的长度。

element_value

values[num_values]

每一项记录数组中的值。

array_value

value

 

注:从这个结构中,我们也可以得出annotation中可以设置的值类型:

1.       基本类型值(bytechardoublefloatintlongshortboolean

2.       字符串(String

3.       枚举(enum

4.       类实例(Class

5.       嵌套注解类型(annotation

6.       以上所有以上类型的一维数组。

相关文章
|
11月前
|
Java Unix Go
【Java】(8)Stream流、文件File相关操作,IO的含义与运用
Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中。!但本节讲述最基本的和流与 I/O 相关的功能。我们将通过一个个例子来学习这些功能。
401 1
|
自然语言处理 前端开发 算法
Java编译器优化秘籍:字节码背后的IR魔法与常见技巧
编译器将源代码转换为机器码的过程中,会经历多个中间表达形式(IR)的转换与优化。前端生成高级IR(HIR),后端将其转为低级IR(LIR)并进行机器相关优化。Java编译流程包括源码到字节码、再由即时编译器转换为内部HIR(如SSA图)、优化后生成LIR,最终编译为机器码。常见优化技术包括常量折叠、值编号、死代码消除、公共子表达式消除等,旨在提升程序性能与执行效率。
454 0
|
存储 Java 编译器
深入理解Java虚拟机--类文件结构
本内容介绍了Java虚拟机与Class文件的关系及其内部结构。Class文件是一种与语言无关的二进制格式,包含JVM指令集、符号表等信息。无论使用何种语言,只要能生成符合规范的Class文件,即可在JVM上运行。文章详细解析了Class文件的组成,包括魔数、版本号、常量池、访问标志、类索引、字段表、方法表和属性表等,并说明其在Java编译与运行过程中的作用。
400 0
|
存储 人工智能 Java
java之通过Http下载文件
本文介绍了使用Java实现通过文件链接下载文件到本地的方法,主要涉及URL、HttpURLConnection及输入输出流的操作。
861 0
|
监控 Java API
Java语言按文件创建日期排序及获取最新文件的技术
这段代码实现了文件创建时间的读取、文件列表的获取与排序以及获取最新文件的需求。它具备良好的效率和可读性,对于绝大多数处理文件属性相关的需求来说足够健壮。在实际应用中,根据具体情况,可能还需要进一步处理如访问权限不足、文件系统不支持某些属性等边界情况。
566 14
|
存储 Java 数据安全/隐私保护
Java技术栈揭秘:Base64加密和解密文件的实战案例
以上就是我们今天关于Java实现Base64编码和解码的实战案例介绍。希望能对你有所帮助。还有更多知识等待你去探索和学习,让我们一同努力,继续前行!
787 5
|
网络协议 安全 Java
实现Java语言的文件断点续传功能的技术方案。
像这样,我们就完成了一项看似高科技、实则亲民的小工程。这样的技术实现不仅具备实用性,也能在面对网络不稳定的挑战时,稳稳地、不失乐趣地完成工作。
650 0
|
前端开发 JavaScript Java
Java中将图片转换为base64格式的技巧
这样,你就可以在Java中将图片转换为Base64格式了。这个方法的实现非常简单,只需要使用Java的内置库,无需任何额外的库。希望这个方法对你有所帮助。
1032 22
|
前端开发 Cloud Native Java
Java||Springboot读取本地目录的文件和文件结构,读取服务器文档目录数据供前端渲染的API实现
博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
Java||Springboot读取本地目录的文件和文件结构,读取服务器文档目录数据供前端渲染的API实现
|
Java API 数据处理
深潜数据海洋:Java文件读写全面解析与实战指南
通过本文的详细解析与实战示例,您可以系统地掌握Java中各种文件读写操作,从基本的读写到高效的NIO操作,再到文件复制、移动和删除。希望这些内容能够帮助您在实际项目中处理文件数据,提高开发效率和代码质量。
1067 4