javac -parameters 标志的缺点

Drawbacks of javac -parameters flag

我想尝试一些在运行时需要参数名称的框架功能,所以我需要使用 -parameters 编译我的应用程序,它会将参数名称存储在 JVM 字节码中。

除了 jar/war 的大小外,此参数的使用存在哪些缺点?

只有 会改变 .class 的大小,因为字节码现在将包含更多信息:

public class DeleteMe3 {
    public static void main(String[] args) {
    }

    private static void go(String s) {
    }
}

例如,这将包含有关参数名称的信息,如下所示:

private static void go(java.lang.String);
   descriptor: (Ljava/lang/String;)V
   flags: ACC_PRIVATE, ACC_STATIC
   Code:
     stack=0, locals=1, args_size=1
       0: return
     LineNumberTable:
       line 11: 0
   MethodParameters:
     Name                           Flags
     s

如果没有 -parameters,这个 MethodParameters 就不会出现。

可能有些框架不适合这个。这是一个 Spring Data JPA Issue。我知道它是因为我们前段时间遇到它并且不得不升级(从那以后我没有遇到过任何其他人)。

class 文件格式中添加的参数名称已包含在 JEP 118, which was delivered in Java 8. There was a little bit of discussion about why inclusion of parameter names was made optional in OpenJDK email threads here and here 中。简而言之,将参数名称设为可选的原因是担心 class 文件大小、兼容性面和敏感信息的暴露。

兼容性面的问题值得一些额外的讨论。上面链接的线程之一说更改参数名称是二进制兼容的更改。这是事实,但仅在 JVM 的二进制兼容性概念的严格上下文中。也就是说,更改方法的参数名称永远不会改变该方法是否可以被 JVM 链接。但该声明通常不支持兼容性。

从历史上看,参数名称被视为局部变量名称。 (毕竟,它们在范围内是局部的。)您可以随意更改它们,方法之外的任何内容都不会受到影响。但是,如果您启用对参数名称的反射访问,突然间您无法在不考虑程序的其他部分可能正在使用它的情况下更改名称。更糟糕的是,没有什么可以告诉你的,除非你对所有参数名称的使用都有严格的测试用例,或者你有一个非常好的静态分析器可以找到这些用例(我不知道有一个)。

评论链接到关于使用 Jackson(一个 JSON 处理库)的问题,它具有将方法参数名称映射到 JSON 属性 名称的功能。这可能非常方便,但也意味着如果更改参数名称,JSON 绑定可能会中断。更糟糕的是,如果程序根据 Java 方法参数名称生成 JSON 结构,那么更改方法参数名称可能会悄悄更改数据格式或线路协议。显然,在这样的环境中,可靠地使用此功能意味着您必须进行非常好的测试,并在代码周围添加注释以指示不得更改哪些参数名称。