描述符
定义
一个描述符是一个表示一个字段或者方法类型的字符串。描述符通常是在class文件中用UTF-8的字符串来表示。
描述符的语法符号
描述符用一种语法来进行规范。描述符的这种语法是一组形成各种语法正确的描述符的字符序列。
描述符分类
字段描述符(Field Descriptors)
字段描述符用来表示一个类,实例或者局部变量。以下就是所有的字段描述符:
B C D F I J S Z 都是基本类型在class文件中的表现形式。
"Ljava/lang/String;“则是String类型在class文件中的表现形式,L表示其后的字符串是一个类名,以”;"结尾。
数组在java中也是一个引用类型,数组在class文件中的表现形式为"[",一个double[][]在class文件中的表现形式为[[D,[后面可以跟其他的字段描述符。
方法描述符(Method Descriptors)
一个方法描述符包含0个或者多个参数描述符(参数都是字段描述符),它表现形式为:({ParameterDescriptor}) ReturnDescriptor。
一般情况下,一个有返回值的方法表现为:({ParameterDescriptor}) ReturnDescriptor。
1 2 3 4 5 6 java方法:String test(int i , double d , String s) class形式:(IDLjava/lang/String;)Ljava/lang/String; int i 对应 I double d 对应 D String s 对应 Ljava/lang/String; 返回值String对应 Ljava/lang/String;
如果是无返回值的方法,则表现为:({ParameterDescriptor}) V
1 2 3 4 5 6 java方法:void test(int i , double d , String s) class形式:(IDLjava/lang/String;)V int i 对应 I double d 对应 D String s 对应 Ljava/lang/String; 无返回值 对应 V
如果方法参数总长度在255之内(这个长度包括了实例的this或接口方法调用,long和double占2个长度,其他的占一个长度),则判定一个方法描述符是有效的。
无论是一个类方法还是一个实例方法,方法相同的话,塔就是同一个方法描述符。虽然一个实例方法传递了this这个本对象引用,但是这个this不会在方法描述符中反映。这个this引用是通过java虚拟机的用来调用实例方法的指令来传递的。
代码举例
下面是我们需要的代码
1 2 3 4 5 public class Test { public static void main (String[] args) { System.out.println("Hello world" ) ; } }
代码编译后,我们通过javap命令,获取class文件的详细信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 javac Test.java javap -v Test Classfile /home/share/Public/blog/source/_posts/Java/jvm/Test.class Last modified 2020 -1 -17 ; size 413 bytes MD5 checksum adae6df967b28789efc582efe75101db Compiled from "Test.java" public class Test minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #6.#15 // java/lang/Object."<init>":()V #2 = Fieldref #16.#17 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #18 // Hello world #4 = Methodref #19.#20 // java/io/PrintStream.println:(Ljava/lang/String;)V #5 = Class #21 // Test #6 = Class #22 // java/lang/Object #7 = Utf8 <init> #8 = Utf8 ()V #9 = Utf8 Code #10 = Utf8 LineNumberTable #11 = Utf8 main #12 = Utf8 ([Ljava/lang/String;)V #13 = Utf8 SourceFile #14 = Utf8 Test.java #15 = NameAndType #7:#8 // "<init>":()V #16 = Class #23 // java/lang/System #17 = NameAndType #24:#25 // out:Ljava/io/PrintStream; #18 = Utf8 Hello world #19 = Class #26 // java/io/PrintStream #20 = NameAndType #27:#28 // println:(Ljava/lang/String;)V #21 = Utf8 Test #22 = Utf8 java/lang/Object #23 = Utf8 java/lang/System #24 = Utf8 out #25 = Utf8 Ljava/io/PrintStream; #26 = Utf8 java/io/PrintStream #27 = Utf8 println #28 = Utf8 (Ljava/lang/String;)V // 这个方法描述符表示:void func(String s) { public Test () ; 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 1 : 0 public static void main (java.lang.String[]) ; descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2 , locals=1 , args_size=1 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String Hello world 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8 : return LineNumberTable: line 3 : 0 line 4 : 8 } SourceFile: "Test.java"
文献引用
JNI字段描述符