类文件本身中实际上没有任何内容存储方法参数的名称。如果您查看第 4.3.3 节,您将看到以下定义MethodDescriptor
:
方法描述符表示该方法采用的参数和它返回的值:
MethodDescriptor:
( ParameterDescriptor* ) ReturnDescriptor
A parameter descriptor represents a parameter passed to a method:
ParameterDescriptor:
FieldType
返回描述符表示从方法返回的值的类型。它是由语法生成的一系列字符:
ReturnDescriptor:
FieldType
VoidDescriptor
VoidDescriptor:
V
字符 V 表示该方法不返回任何值(其返回类型为 void)。
如果您打印出用于Person.class
和PersonImpl.class
使用的字节码,您可以看到这一点javap -c
:
Compiled from "Person.java"
public interface Person {
public abstract void setName(java.lang.String);
public abstract void setAge(int);
}
Compiled from "PersonImpl.java"
public class PersonImpl implements Person {
public PersonImpl();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void setName(java.lang.String);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
10: ldc #5 // String This is my name:
12: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: aload_1
16: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
25: return
public void setAge(int);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
10: ldc #9 // String This is my age:
12: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: iload_1
16: invokevirtual #10 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
25: return
}
您可以看到该方法的签名没有说明参数的名称。只有它的类型。
我怀疑正在发生的是 JD-Gui 可能正在使用某种基于 JavaBeans 约定的启发式方法来派生参数的名称。由于方法的名称是setName
,它假定参数的名称是name
。尝试将参数名称更改为其他名称,name
然后查看 JD-Gui 打印的内容。
-g
如果您使用or进行编译,将显示调试信息,例如局部变量-g:vars
;默认情况下不显示。这些显示在LocalVariableTable
属性中。从第 4.7.13 节开始:
该LocalVariableTable
属性是属性的属性表中的可选可变长度属性Code
(第 4.7.3 节)。调试器可以使用它来确定方法执行期间给定局部变量的值。
注意可选部分;这就是为什么您默认看不到它的原因。现在,如果您查看第 4.7.3 节的Code
属性:
Code 属性是 method_info 结构(第 4.6 节)的属性表中的可变长度属性。属性包含Code
Java 虚拟机指令和方法的辅助信息,包括实例初始化方法或类或接口初始化方法(第 2.9 节)。
如果方法是本机或抽象方法,则其结构在其属性表中method_info
不得有属性。Code
Code
否则,它的 method_info 结构在其属性表中必须只有一个属性。
由于接口方法定义实际上是抽象的(除非您使用默认方法),因此您不会看到LocalVariableTable
它们的条目。我用最新版的JD-Gui针对PersonImpl.class
那个没有用编译的-g
,发现没有显示name
和age
。相反,它显示出来paramString
,paramInt
就像你看到的一样Person.class
。但是,如果您使用-g
标志编译它,您将看到name
and age
。