在编译 Java 类时禁用编译时依赖关系检查

2022-09-04 06:47:30

请考虑以下两个 Java 类:

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

b.) class Test { void foo(pkg.not.in.classpath.FooBar foobar) { } }

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

第一个类将使用标准javac编译良好。

但是,第二个类不会编译,javac将为您提供错误消息 。"package pkg.not.in.classpath does not exist"

在一般情况下,错误消息很好,因为检查依赖项可以让编译器告诉您是否错误了某些方法参数,等等。

虽然在编译时对依赖关系的检查很好且很有帮助,但在上面的示例中,生成Java类文件并不严格需要AFAIK。

  1. 您能举出任何示例,说明在不执行编译时依赖关系检查的情况下,在技术上不可能生成有效的 Java 类文件吗?

  2. 您知道有没有办法指示javac或任何其他Java编译器跳过编译时依赖关系检查?

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


答案 1

您能举出任何示例,说明在不执行编译时依赖关系检查的情况下,在技术上不可能生成有效的 Java 类文件吗?

请考虑以下代码:

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

如果目标方法具有 签名 ,则将生成以下指令: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

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

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

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


答案 2

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

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

因此,您的前提 - 编译器不需要在这种情况下找到要编译的类 - 是不正确的。

编辑 - 您的评论似乎在问“编译器不能忽略这个事实并生成无论如何都合适的字节码吗?

答案是否定的 - 它不能。根据 Java 语言规范,方法签名必须采用类型,这些类型在其他地方被定义为在编译时可解析。

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


推荐