【问题标题】:How to share package private data between two packages in Java?如何在 Java 中的两个包之间共享包私有数据?
【发布时间】:2012-06-14 22:26:41
【问题描述】:

我有 2 个 Java 包,A 和 B。假设包 B 中的某些类想要使用包 A 中的某些类,但是,当开发人员出现并开发包 C(或者说,应用程序 C)时,他/她将使用我的包 B,但我希望他/她能够使用 B 正在使用的 A 中的类。也就是说,我希望我在包 A 中的类是包私有的,以便对应用程序开发人员隐藏它们。但是,我确实希望我自己的包 B 能够访问那些包私有的类。这可以用Java完成吗?我是否基本上只需要硬着头皮将课程公开并希望用户不要尝试使用它们?或者,我是否需要将 A 中的类复制到 B 中?

我的偏好不是 hack-y(即我不想使用反射)。帮忙?

【问题讨论】:

  • 如果包 B 可以对类包 A 做某事,那么没有什么可以阻止包 C 对类包 A 做同样的事情。但是,可以阻止包 C 获取实例包 A 中的一个类,它是包 B 中的一个类的成员(除非涉及反射)。
  • 如果你想要安全,不要在解释器上编写代码?
  • 听起来包 A 和 B 真的应该在同一个包中,或者某种返回私有实现的工厂是必要的。
  • @nhahtdh -> 您能否解释一下,如您所说,“阻止包 C 获取包 A 中的类的实例,该实例是包 B 中的类的成员“?
  • @David -> 你能解释一下如何创建一个“返回私有实现的工厂”吗?

标签: java package share encapsulation package-private


【解决方案1】:

您可以使用JDK 8 及其Project Jigsaw 来实现。你可能想看看Project Jigsaw Quickstart Guide

不幸的是,Jigsaw 是 JDK8 的一部分,还没有完全准备好。预计功能不完整until January 2013,不会在 2013 年年中之前发布。

但是,您已经可以使用 JDK 8 预览版编译您的类,并使您的想法付诸实践。

在这种情况下,您的问题可以通过将您的应用程序划分为独立的模块来解决。你可以这样做:

module foo {
    exports foo;
    permits bar;
    permits baz;
}

这里只有名为 bar 或 baz 的模块需要模块 foo。某个其他名称的模块对 foo 的依赖在编译时、安装时或运行时将无法解析。如果不存在许可条款,则不存在此类限制。

不确定像 OSGI 这样的替代框架(您可以在 Apache FelixEclipse Equinox 中找到实现)是否提供某种功能来实现这些级别的封装。您可能想对此进行一些调查。

OSGi 不存在 Jigsaw 的问题在于,框架强制执行的任何规则都可以通过反射来破坏,但是一旦 Jigsaw 准备好供公众使用,这些规则将由 Java 本身强制执行,正如您所阅读的上面,在编译时、运行时和安装时。

【讨论】:

  • 感谢您的好评(我投了赞成票)。不幸的是,我的目标是 Android 和 JDK 6... :-/ 关于我可能做的任何其他想法?
  • @fatfreddyscat OSGI 可能是你最好的选择,但实现起来也不容易。
  • 请注意,Jigsaw 项目没有进入 Java 8,它现在针对 Java 9。
【解决方案2】:

您可以使用 OSGi 做到这一点。在这种情况下,作为目标的 Android 和 JDK 6 不是问题,在 Android 上运行 OSGi 框架 -> 例如见mBedded Server for Android。您可以从该链接下载免费的非商业版本。

您有多种选择如何在 OSGi 中执行此操作,具体取决于您想要实现的目标。

选项 1(推荐): 您可以将包 A 和 B 放在同一个包 AB 中,并使用 Export-Package 在此包的清单中仅导出包 B。 包/应用程序 C 或任何其他“用户”应用程序可以导入包 B 并使用它。它不能使用,甚至看不到包 A,因为它是包 AB 的内部。您不需要任何 Java 级别的特殊声明或依赖项;这将适用于任何 Jva 版本,因为模块化和单独的捆绑空间是 OSGi 基础的一部分,并且不依赖于最新的 Java 版本或其他东西。

选项 2: 如果出于某种原因您希望将包 A 和 B 分开在不同的包中,您可以让它们如此,您将在清单中导出和导入包,然后使用权限控制哪个包有权导入哪个包(请参阅 OSGi许可和条件许可服务)。但是,这实现起来比较复杂。

选项 3:您也可以将包 A 放在 Fragment 包中,并允许它附加到包含 B 的包。这样 B 将可以访问包 A,但同时您将能够更新如果需要,请在运行时单独打包 A。由于片段中的包被视为主机包的私有包(在这种情况下,主机是包含包 B 的包),包 C 不会看到 A。它只会看到包 B 导出的内容。

由于您对 OSGi 不太熟悉,我建议您从选项 1 开始,然后如果需要,您可以根据需要将您的方法升级到选项 3。

@Edwin Dalorzo:OSGi 中的规则可以通过反射来破坏,这绝对不是真的。 Bundle 在 OSGi 中有单独的类加载器。您可以从 Bundle C 中尽可能多地反映 A 类,而您唯一会得到的是 ClassNotFound 异常 - 相信我,我已经看过很多次了;)

【讨论】:

  • 感谢您的详细解答!!就我而言,包 C 需要同时访问包 A 和包 B;只是我希望包 B 能够访问 A 中的“包私有”类......如果 Java 支持“朋友”的概念(如在 C++ 中),那么它可以这样工作。我认为这种 OSGi 方法可能对我有用,但是,由于我时间紧迫,我可能会只使用我的“hackjob 解决方案”(请参阅​​我对原始帖子的“UPDATE”评论) 时不时地,当我有时间时,考虑使用你的方法。再次谢谢你!投票!
  • 如果您只想导出选项1中包A的一部分,这也是可以的。在清单的 Export-Package 条目中使用“include”或“exclude”导出指令:“include – 一个逗号分隔的类名列表,必须对导入器可见。注意在值中使用逗号要求用双引号括起来。有关类过滤,请参阅第 50 页的类过滤。"
猜你喜欢
  • 1970-01-01
  • 2021-06-06
  • 1970-01-01
  • 2015-09-08
  • 2013-02-25
  • 2015-01-31
  • 1970-01-01
  • 2017-06-01
  • 2022-01-03
相关资源
最近更新 更多