【问题标题】:Compile Java code without dependencies [duplicate]编译没有依赖关系的Java代码[重复]
【发布时间】:2014-07-14 00:48:21
【问题描述】:

我有一个 java 程序的源代码,但我没有它的依赖项。是否可以编译使用无法解析的字段、类和方法的 Java 代码?如果没有,是否有程序或 Eclipse 插件会在编译期间自动生成无法解析的假类、变量和方法?请举例说明。

public class Main {
    public static void main(String[] args) {
        // ...
        UnknownClass.unknownMethod();
    }
}

我希望它使用 unknownMethod() 方法自动生成 Class UnknownClass:

public class UnknownClass {
    public static void unknownMethod() {}
}

但不在输出 .jar 中导出它

【问题讨论】:

  • 如果您需要这些类的依赖项,您可以自己下载并将它们放在类路径中,也可以使用 Maven 或 Gradle 等工具为您管理和下载它们。
  • 不,它们不是供下载的,是否可以在编译过程中简单地生成一个假的方法和变量来编译调用未知方法的代码?
  • 理论上你可以......但这在实践中是行不通的,因为代码显然取决于那里的那些类。如果由于某种原因无法下载这些依赖项,则可能会卡住。
  • @Makoto 你的意思是,当 Java 代码编译时,它使用来自使用的类和方法的信息?那么人们是如何创建 API 的呢?
  • @Makoto 但是人们如何创建 API?例如 Bukkit 和 Craftbukkit (bukkit.org)。 Craftbukkit 是实际的程序,Bukkit 只是 API,只包含方法,没有内部代码。但是,当为 Bukkit 编译插件时,它也可以与 CraftBukkit 一起使用。

标签: java compilation


【解决方案1】:

是否可以编译使用无法解析的字段、类和方法的 Java 代码?

没有。源代码的静态依赖项必须在编译时都可用。

如果没有,是否有程序或 Eclipse 插件会在编译期间自动生成无法解析的假类、变量和方法?

AFAIK,不。

事实上,我认为构建这样一个程序在技术上是不可能的。这将需要推断我们没有任何信息的类和方法的签名。我认为不可能准确地做到这一点。即足够准确,签名将匹配真实类的实际签名。

(需要解决的一些问题是推断类的正确超类型,推断方法的参数和结果的正确类型,推断方法是否具有可变参数,推断方法是否存在重载,等等上。这些问题有些是可以解决的,有些则绝对不是。)


但是 Bukkit 是如何使用 CraftBukkit.jar 和 Bukkit.jar 做到的呢?在 Bukkit.jar 中,有没有内部代码的方法头,但是在为 BUkkit.jar 编译代码时,它可以与 Craftbukkit.jar 一起使用。

我想你已经回答了你自己的问题。类层次结构和方法标头位于提供的 Bukkit JAR 文件中。因此,它们不需要被推断。

相比之下,您在这里要求做的是从一个干净的状态推断类层次结构和方法签名......加上使用它们的代码(您的源代码)隐含的一些约束。


这是一个例子:

   UnknownClass c = ...
   c.method(42);
   c.method(42.0);

对此有多种不同的解决方案:

   public class UnknownClass ... {
       void method(double arg) {...}
   }

   public class UnknownClass ... {
       int method(double arg) {...}
   }

   public class UnknownClass ... {
       void method(int arg) {...}
       void method(double arg) {...}
   }

   public class UnknownClass ... {
       void method(byte arg) {...}
       void method(double arg) {...}
   }

   public class UnknownClass ... {
       void method(double... arg) {...}
   }

等等。

问题:哪个是正确的?即与真实UnknownClass中的实际签名匹配的那个?

答案:我们无从得知!这很重要,因为如果我们弄错了,当您尝试针对包含真实类的 JAR 运行编译后的代码时,可能会出现类加载器错误。

【讨论】:

  • 但是 Bukkit 是如何使用 CraftBukkit.jar 和 Bukkit.jar 做到的呢?在 Bukkit.jar 中,有没有内部代码的方法头,但是在为 BUkkit.jar 编译代码时,它可以与 Craftbukkit.jar 一起使用。
  • 你的意思是编译后的代码比源代码包含更多的信息吗?
  • @Victor2748 - 不。这不是问题。
  • 同意准确推断签名是一个难题(并且它可能与缺少的库不匹配),但我不一定会说这是不可能的。 Eclipse 非常有能力生成有效的类文件,即使您在其源代码中间有一个大错字和红色曲线(仅在您尝试运行该部分代码时抛出异常,但这是一个不同的问题)。也有创建方法的自动建议。从现有代码库中准备缺失存根的代码分析工具似乎并非遥不可及(确实需要付出一些努力)。
  • @Bruno - 这不仅仅是生成可能的解决方案的问题。解决方案必须匹配类中的实际签名。实际上,可以有多种不同的解决方案来满足约束;见例子。问题是,如果您推断错误,您生成的代码会由于二进制不兼容而在运行时失败。简而言之,“工具”是不可靠的……可能到了无用的地步。
猜你喜欢
  • 2018-06-19
  • 2013-08-31
  • 2017-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-22
相关资源
最近更新 更多