【问题标题】:Check if object is instanceof a protected class检查对象是否是受保护类的实例
【发布时间】:2014-08-20 14:23:47
【问题描述】:

假设我正在使用具有以下方法的 Java 库

public static SomeInterface foo();

接口SomeInterface 有多个实现,其中一些是库包中的protected。其中一种实现是TheProtectedClass

检查foo() 返回的对象是否是TheProtectedClass 的实例的最佳方法是什么?

我目前的计划是创建一个 Utils 类,它存在于我的项目中,但与受保护的类在同一个包中。这个 Utils 可以引用TheProtectedClass,因为它在同一个包中,因此它可以检查对象是否为instanceof TheProtectedClass

还有其他想法吗?

编辑:有些人在问“为什么”,所以这里有更多上下文。

我正在使用jOOQ,在我的代码的某些部分,我想知道我拥有的Field 实例是否是Lower 的实例。

目前,我使用 field.getName().equals("lower"),但这并不像我希望的那样强大。

我意识到,由于Lower 是一个受保护的类,它不是 API 的一部分,它可以更改,但我可以接受。

【问题讨论】:

  • 你可以通过反射来做到这一点,但你为什么要这样做呢?
  • 多个实现,其中一些是受保护的你是什么意思。一个类具有publicdefault 可见性。
  • 当然,最好的方法是避免首先检查instanceof
  • 当实例的任何超类或超接口为protectedprivate 或包私有时,它是否受到保护
  • 了解用例背后的基本原理会很有趣。也许您真正想做的事情可以使用 jOOQ API 以其他方式实现?

标签: java protected instanceof jooq


【解决方案1】:
Class.forName("TheProtectedClass").isAssignableFrom(foo())

尽管出于多种原因这是一个坏主意。你在这里打破了封装和抽象。如果它是包私有的,那么您不必在外面关心它。如果它是受保护的,你应该显式地继承它并使用类提供的API来处理这种情况。

不太明显但更正确的解决方案是获取TheProtectedClass 的实例,并通过它进行比较

guaranteedTPCInstance.getClass().isAssignableFrom(foo())

,虽然仍然有点 hacky,但至少更便携和 OOPy IMO。

关于您在与 TheProtectedClass 相同的包中创建一个类以避免包私有的想法 - 这是一个可行的解决方案,但是 a) 它违反了封装的基本原则和 TPC 类的编程合同;打包由库/类作者完成是有原因的 - 以防止不负责任的数据访问和使用私有 API 或未记录的专有方法,b) 这并不总是可能的(并且不应该在适当的情况下是可能的设计的库类),因为这些类不仅可以是包私有的,而且可以是final 或有效的最终类(匿名内部类等) - 由于 Bloch 在 EJ 2nd 中描述的原因,“优先组合而不是继承”项,另请参见Good reasons to prohibit inheritance in Java? Use of final class in Java 等 c) 你不能用一些 Java 库类来做,因为你不能定义你的类来使用例如java.lang 包。因此,唯一的“便携式”解决方案是通过反思和我所描述的。

tl;dr 事实上,你可以通过模仿包定义来搭载另一个包,这显然是 Java 语法的 C 风格缺陷(允许程序员做他通常不能做的事情;一些特定的反射也是如此方法);以这种方式进行的 hack 既不可维护也不安全。

注意:如果您希望在 internal implementation-dependent 中做某事,同时 portablemaintainable (例如,不受实现更改/类名更改等)的影响,您显然期待不可能的事情。

【讨论】:

  • 我发现这个解决方案不如我帖子中提出的 Utils 解决方案,因为如果 TheProtectedClass 在库版本之间更改名称,它不会破坏编译。
  • 1) 您要求 其他想法 - 没有任何其他方法可以做到这一点,因此它不如您提出的解决方案(可以说)这一事实仅强调了这一点您要实现的目标本身就是 hacky,2)请参阅下面的我的编辑以获得更便携的版本,不依赖于 TPC 类名称,3)如果您不想从其名称或实例推断受保护类对象,您希望如何向应用程序显示“我在谈论 this 特定类”?
  • @LukasEder a) 你有没有考虑过这样一个事实:在非显式记录的继承情况下允许继承本身就是一种反模式? ...更不用说继承本身通常是一种反模式,因为大多数人只是不能正确地做到这一点,正如 OP 问题所示 - 这正是 Bloch(不仅是他,因为“优先组合而不是继承”是一种常见的良好编程实践,而不是综合规则,请参阅en.wikipedia.org/wiki/Composition_over_inheritance) cdiscusses 深入。
  • 这正是 Bloch 和许多其他人(包括我在内)说“如果它没有明确设计为可扩展,则将其定为最终以防止继承。如果它明确设计为可扩展,记录它并制作 API直截了当,这样它就可以被继承而不会引入错误和杂项”;因为,在这种情况下,解决方案由于 OP 要求与 jOOQ API 提供的功能而造成的,它证明了类不应该允许继承到外部代码。我不会离题的方法和为什么这样做(有关于它的好书),事实仍然存在。
  • 顺便说一句,如果程序员可以模拟包定义来强制继承,那么包私有解决不了任何问题 - 所以它是定义上的反模式,是通过默默无闻进行安全代码设计的变体反模式。
【解决方案2】:

似乎最好的解决方案是在您的项目中创建一个与 package-private 类具有相同包的包,并将 TheProtectedClass.class 公开为 Class<?> 或简单地添加一个简单的方法来检查您的 @ 987654323@ 是instanceof TheProtectedClass

这不需要反射,它快速且相对安全(如果包私有类更改名称,编译会中断)。

【讨论】:

    猜你喜欢
    • 2021-11-20
    • 1970-01-01
    • 2013-05-17
    • 2016-07-07
    • 2021-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多