在编译的Java类中保留参数/实参名称

insrf1ej  于 2023-05-05  发布在  Java
关注(0)|答案(6)|浏览(237)

当我编译这样的代码时:

public class MyClass
{
    void myMethod(String name, String options, String query, String comment)
    {
        ...
    }
}

并将其编译为类文件,似乎参数名称丢失了。也就是说,当一些其他Java代码引用MyClass并想要调用或覆盖myMethod时,我的IDE(目前是Eclipse)似乎从类文件中获得了这个方法签名:

void myMethod(String arg0, String arg1, String arg2, String arg3);

我知道Eclipse(可能还有其他IDE)允许我提供MyClass的源代码或Javadoc (正如Bishiboosh所指出的) 的链接,并且可以利用这一点。但是我很好奇是否有某种方法可以告诉javac将参数名包含到类文件中,这样即使该类的用户只有类文件,他们也可以看到参数名。

类解决方案

当我用java -g:vars编译一个类时,参数的名称包含在类文件中。-g:vars似乎等同于 Eclipse -〉project properties -〉Java compiler -〉Add variable attributes to generated class files
这个解决方案是由几位作者提出的,但尼克的回答最终让我相信了。
在我的机器上,Eclipse有时使用这些信息,有时不使用,这可能是我的错或Eclipse中的错误,但不是类文件或编译器的问题。无论如何,现在我知道信息肯定是存在的。

但没有接口解决方案

虽然这对类来说工作得很好,但对接口来说却不起作用。
对我来说,合乎逻辑的原因似乎是,-g:vars只提供了局部变量的名称,这也是javac的文档所声明的。在方法的主体中,它的参数与局部变量非常相似,因此它们被-g:vars覆盖。接口方法没有主体,所以它们不能有局部变量。
我最初的问题只是问班级,因为我不知道可能有任何区别。

类文件格式

正如 gid 指出的,类文件格式不支持存储参数名。我在类文件规范中发现了一个描述数据结构的部分,该数据结构应该包含方法的参数名称,但在编译接口时肯定不会使用。
在编译类时,我无法判断是否使用了上述数据结构,或者Eclipse是否从方法体中参数的使用推断出参数名。Maven可以澄清这一点,但我认为这并不重要。

hgncfbus

hgncfbus1#

要保留类文件中的名称以用于调试,请尝试项目属性、Java编译器,然后“向生成的类文件添加变量属性”(请参阅Eclipse Help)。
编译以下源代码:

public class StackOverflowTest {
    public void test(String foo, String bar) {
        // blah
    }
}

反编译为:

// Compiled from StackOverflowTest.java (version 1.5 : 49.0, super bit)
public class StackOverflowTest {

    // Method descriptor #6 ()V
    // Stack: 1, Locals: 1
    public StackOverflowTest();
        0  aload_0 [this]
        1  invokespecial java.lang.Object() [8]
        4  return
        Line numbers:
            [pc: 0, line: 1]
        Local variable table:
            [pc: 0, pc: 5] local: this index: 0 type: StackOverflowTest

    // Method descriptor #15 (Ljava/lang/String;Ljava/lang/String;)V
    // Stack: 0, Locals: 3
    public void test(java.lang.String foo, java.lang.String bar);
        0  return
        Line numbers:
            [pc: 0, line: 4]
        Local variable table:
            [pc: 0, pc: 1] local: this index: 0 type: StackOverflowTest
            [pc: 0, pc: 1] local: foo index: 1 type: java.lang.String
            [pc: 0, pc: 1] local: bar index: 2 type: java.lang.String
}

请参见参数名称保留在类文件中。
我建议你看看你的源代码是如何编译的,它是为哪个版本编译的等等。

编辑:

啊,我看到这是不同的接口-他们似乎没有这些信息可用于调试器,我想这是有道理的。我不认为会有一个绕过这个的方法,如果你只是想在编辑源代码时看到参数名,你需要像Nagrom_17建议的那样走javadoc路线(附加源代码)。

z0qdvdin

z0qdvdin2#

您不需要特别的源代码来使参数名出现在Eclipse中……如果您指定Javadoc,Eclipse将显示参数。

ojsjcaue

ojsjcaue3#

使用调试支持进行编译可能会有所帮助,调试支持将所有名称存储在.class文件中。
虽然我不知道Eclipse是否考虑到了这一点。

jc3wubiy

jc3wubiy4#

如果在类文件中包含调试信息,Eclipse将获取参数的名称:javac -g:vars就足够了。

e37o9pze

e37o9pze5#

在类文件数据结构中不支持将参数名存储到任何方法中,不管您使用什么javac选项。
为了在IDE中查看原始名称,您必须提供javadoc或源代码。
如果你有一个特殊的需要,在运行时获得它们,可以添加注解的参数,但你必须创建自己的,因为没有一个标准的设置使用。
抱歉真是太有帮助了

编辑:我完全更正了...类文件格式确实有命名参数的空间(JLS 4.7)

我不明白的是你怎么能用java.lang.reflect.*来访问它们

drkbr07n

drkbr07n6#

您不需要单独的Javadoc文件,您可以在Eclipse中使用在多行注解的第一个斜杠后带有两个星号(*)的特殊注解来创建'内联' javadoc。
示例代码:

public class MyClass
{
 /**
  * documentation of your method
  * 
  * @param name    a String describing the name
  * @param options used to describe current option
  * @param query
  * @param comment
  * @return void
  */
    void myMethod(String name, String options, String query, String comment)
    {
        ...
    }
}

相关问题