编译Java类时禁用编译时依赖性检查

kno*_*orv 12 java jvm bytecode javac

考虑以下两个Java类:

a.) class Test { void foo(Object foobar) { } }

b.) class Test { void foo(pkg.not.in.classpath.FooBar foobar) { } }
Run Code Online (Sandbox Code Playgroud)

此外,假设pkg.not.in.classpath.FooBar在类路径中找不到.

第一个类将使用标准javac进行编译.

但是,第二个类不会编译,javac会给你错误信息"package pkg.not.in.classpath does not exist".

在一般情况下,错误消息很好,因为检查依赖项允许编译器告诉您是否有一些方法参数错误等.

虽然很好,也很有帮助,但在编译时检查依赖项是非常严格需要AFAIK 来生成上面示例中的Java类文件.

  1. 您是否可以提供在不执行编译时依赖性检查的情况下在技术上无法生成有效Java类文件的示例?

  2. 您是否知道有任何方法可以指示javac或任何其他Java编译器跳过编译时依赖性检查?

请确保您的答案解决了这两个问题.

McD*_*ell 19

您是否可以提供在不执行编译时依赖性检查的情况下在技术上无法生成有效Java类文件的示例?

考虑以下代码:

public class GotDeps {
  public static void main(String[] args) {
    int i = 1;
    Dep.foo(i);
  }
}
Run Code Online (Sandbox Code Playgroud)

如果目标方法具有签名public static void foo(int n),则将生成以下指令:

public static void main(java.lang.String[]);
  Code:
   0:   iconst_1
   1:   istore_1
   2:   iload_1
   3:   invokestatic    #16; //Method Dep.foo:(I)V
   6:   return
Run Code Online (Sandbox Code Playgroud)

如果目标方法具有签名public static void foo(long n),则将在方法调用之前int提升为long:

public static void main(java.lang.String[]);
  Code:
   0:   iconst_1
   1:   istore_1
   2:   iload_1
   3:   i2l
   4:   invokestatic    #16; //Method Dep.foo:(J)V
   7:   return
Run Code Online (Sandbox Code Playgroud)

在这种情况下,将无法生成调用指令或如何CONSTANT_Methodref_info使用数字16 填充类常量池中引用的结构.有关更多详细信息,请参阅VM规范中的类文件格式.

  • @knorv:你能证明在SO上挥手还是只是挥手吗?;-) (2认同)

And*_*yle 5

我不认为有这样的方法 - 编译器需要知道参数的类,以便创建适当的字节码.如果它找不到Foobar类,则无法编译Test该类.

请注意,虽然您的两个类在功能上是等效的,因为您并未真正使用该参数,但它们并不相同,并且在编译时会产生不同的字节码.

所以你的前提 - 编译器不需要在这种情况下找到要编译的类 - 是不正确的.

编辑 -您的评论似乎在问:"不能编译只是忽略了一个事实,并生成字节码那是适当的呢?"

答案是,不 - 它不能. 根据Java语言规范,方法签名必须采用类型,这些类型在别处定义为在编译时可解析.

这意味着虽然创建一个可以满足您要求的编译器在机械上非常简单,但它会违反JLS,因此在技术上不会是Java编译器.此外,规避编译时安全对我来说听起来不是一个很好的卖点... :-)