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.       以上所有以上类型的一维数组。

相关文章
|
1月前
|
Java
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
74 9
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
77 2
|
1月前
|
Java
轻松上手Java字节码编辑:IDEA插件VisualClassBytes全方位解析
本插件VisualClassBytes可修改class字节码,包括class信息、字段信息、内部类,常量池和方法等。
120 6
|
18天前
|
Java
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
81 34
|
1月前
|
消息中间件 存储 Java
RocketMQ文件刷盘机制深度解析与Java模拟实现
【11月更文挑战第22天】在现代分布式系统中,消息队列(Message Queue, MQ)作为一种重要的中间件,扮演着连接不同服务、实现异步通信和消息解耦的关键角色。Apache RocketMQ作为一款高性能的分布式消息中间件,广泛应用于实时数据流处理、日志流处理等场景。为了保证消息的可靠性,RocketMQ引入了一种称为“刷盘”的机制,将消息从内存写入到磁盘中,确保消息持久化。本文将从底层原理、业务场景、概念、功能点等方面深入解析RocketMQ的文件刷盘机制,并使用Java模拟实现类似的功能。
42 3
|
1月前
|
Java 测试技术 Maven
Maven clean 提示文件 java.io.IOException
在使用Maven进行项目打包时,遇到了`Failed to delete`错误,尝试手动删除目标文件也失败,提示`java.io.IOException`。经过分析,发现问题是由于`sys-info.log`文件被其他进程占用。解决方法是关闭IDEA和相关Java进程,清理隐藏的Java进程后重新尝试Maven clean操作。最终问题得以解决。总结:遇到此类问题时,可以通过任务管理器清理相关进程或重启电脑来解决。
|
1月前
|
存储 缓存 安全
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见。本文介绍了使用 `File.createTempFile` 方法和自定义创建临时文件的两种方式,详细探讨了它们的使用场景和注意事项,包括数据缓存、文件上传下载和日志记录等。强调了清理临时文件、确保文件名唯一性和合理设置文件权限的重要性。
100 2
|
1月前
|
存储 安全 Java
如何保证 Java 类文件的安全性?
Java类文件的安全性可以通过多种方式保障,如使用数字签名验证类文件的完整性和来源,利用安全管理器和安全策略限制类文件的权限,以及通过加密技术保护类文件在传输过程中的安全。
58 4
|
1月前
|
Java 编译器 Maven
Java“class file contains wrong class”解决
当Java程序运行时出现“class file contains wrong class”错误,通常是因为类文件与预期的类名不匹配。解决方法包括:1. 确保类名和文件名一致;2. 清理并重新编译项目;3. 检查包声明是否正确。
64 3
|
1月前
|
存储 Java API
Java实现导出多个excel表打包到zip文件中,供客户端另存为窗口下载
Java实现导出多个excel表打包到zip文件中,供客户端另存为窗口下载
71 4