【问题标题】:Equivalent to C++ header files in Java?相当于Java中的C++头文件?
【发布时间】:2017-04-21 04:50:04
【问题描述】:

我有一个大型 Java 库,我想开发几个较小的应用程序来连接这个库。该库将作为 JAR 出现在目标设备的类路径中,但如果可能的话,我想避免在编译时需要整个库(JAR 或源)。 (如果重要的话,JAR 非常庞大,我也想保护知识产权,尽管这不是我最关心的问题。)

在 C++ 中,我将通过创建 DLL (.so) 并将相关的类和函数定义头复制到我的项目并在编译时将它们添加到包含路径来解决这个问题,让动态链接器在运行时。

如何在 Java 中做到这一点?我的一个想法是删除私有方法/成员,并剥离相关类的方法,以便它们的主体为空,并且在运行时加载具有相同签名的真实类和方法。然而,这种方法看起来非常丑陋和原始,而且需要一些工具来自动化这个过程。有没有工具可以做到这一点?有没有更好的办法?

我不认为它与 this question 重复。该问题的重点是通过删除不必要的类来最小化编译时生成的 JAR 文件的大小。我的意思不是删除未使用的定义,而是完全避免在编译时需要完整的库 JAR。虽然这些是相似的,并且可能有一种方法可以使用 ProGuard 实现我想要的,但链接的问题没有讨论它。

【问题讨论】:

  • 在 Java 中没有等效的头文件。这是一件非常非常非常好的事情。是的,三个'非常'。
  • 嗯,头文件肯定会让人头疼。但这不是我问题的重点。重点是:如何在 Java 中将实现(在编译时不需要知道)与库接口(在编译时必须知道)分开。
  • 没有办法,也没有必要做这一切。在编译和运行时,您必须在类路径中包含依赖项 jar。仅此而已,仅此而已。期间。
  • 你是对的,我曾经使用过你提出的技术,但完全是出于其他原因。在那种情况下,这是为了什么?在编译期间硬盘驱动器中没有足够的空间来保存 JAR?我想这只是一种 C++ 的思维方式。 Java 和 JVM 最初是为了摆脱这种情况而创建的。 C ++中标头的目的是什么?它可以从实际的库实现中抽象出我的代码。即相同的库在 Linux、Solaris、Windows 等中可能不同。JVM 可以绕过这个问题。有没有打算在编译和运行时对该 JAR 进行不同的实现?

标签: java jar shared-libraries javac


【解决方案1】:

如果您的问题只是由于最终 jar 的最小化并且您使用 Apache Maven,您可以尝试在 pom.xml 中声明依赖项时使用“provided”选项。

例如我使用这个依赖声明:

    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcpkix-jdk15on</artifactId>
        <version>1.48</version>
        <scope>provided</scope>
    </dependency>

这意味着我的java编译器使用bouncycastle库进行编译,但最终没有将它包含在最终的jar中。您应该在执行期间提供它。

【讨论】:

  • 谢谢。这实际上解决了我的问题的一部分。如果我将它与@Jiri Tousek 的接口方法结合起来,它可能是解决方案。
  • 算了。 provided 意味着你的巨大 JAR 将在本地机器上,并且在编译期间将在类路径中。此外,只要它是 Maven 并且如果项目不是 EAR 或 WAR(即它是 JAR),那么任何地方都不会包含“巨大的 JAR”。它必须在类路径中。再一次,你试图用它来实现什么?是否有任何意图让您的“巨大 JAR”在编译和运行时有所不同?即使在那种情况下,“界面”的想法也很糟糕。
  • 看看“接口”技术什么时候有意义。有 javax.servlet.api 库,并且(通常)它只有接口(或抽象类)。然后不同的 Servlet 容器有不同的实现(即 WebLogic、WebSphere、TomCat、JBoss AS 等)。所以我可以只使用 javax.servlet.api 编写代码,它可以在任何这些容器上工作。那么,您的“巨大 JAR”是否面临类似要求?
【解决方案2】:

在 Java 中没有头文件的完全等价物,但是可以使用接口来实现在没有实际实现的情况下针对“头文件”(在“合同”的含义中)进行编译:

  • 使用相关方法为您想要“标题”的每个类创建接口
  • 让实际的类实现各自的接口
  • 将接口打包到一个 JAR 中,将实现打包到另一个 JAR 中
    • (如果您使用的是Maven之类的构建工具,请使用两个项目,并让实现项目依赖于接口一个)
  • 只在编译时提供接口 JAR,在运行时都提供

当然需要一些知道实际实现并可以实例化它们的工件,或者您必须使用一些查找来搜索类路径以找到合适的实现。

【讨论】:

  • 好的,好建议。我在想这样的事情。要是不用改类和引入Java接口就好了,不过好像也无能为力了……
  • 如此庞大的工作的原因是什么?我可以想象在适当的包中制作几十万个接口需要什么......为了什么?
  • @JanHadáček 我发布的可能重复问题中的答案提供了不需要样板的解决方案。
猜你喜欢
  • 2013-07-13
  • 2014-09-29
  • 2011-01-21
  • 1970-01-01
  • 1970-01-01
  • 2011-06-29
  • 2010-09-24
  • 2023-04-06
  • 2014-12-11
相关资源
最近更新 更多