Java 反射遵循的规则

99 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 3 天,点击查看活动详情

许多著名的、可靠的和受欢迎的开源库都是基于 Java 反射的。

什么时候使用 Java 反射既好又聪明?什么时候是坏的和危险的?开发人员应该遵循哪些规则,以免在使用反射时头顶上出现狗屎风暴?

1. 不要使用反射来违反其他开发者设定的限制。

这是所有规则中最重要的规则。如果您正在使用来自其他开发人员的一段代码,那么您将按照该开发人员的预期方式获取代码。特别是如果它是已发布 API 的一部分。

  • final关键字——最终确定的字段、方法或类
  • private,protected或 package-private(无修饰符)——有限访问

这些是不应该使用反射修改的东西。

如果库的创建者希望您更改字段或覆盖方法,他/她不会添加final修饰符。特定架构决策背后有其原因。无法访问的代码可能只有在特定的条件下才能正常工作。

“违反”公共 API 合同可能会对您可能没有意识到的代码的其他部分产生负面影响

您“违反”公共 api 合同似乎没有负面影响,但您可能错了,因为您可能对库的了解不够透彻。

2. 公共 API 之外的任何内容都是禁止的。

这直接源自前一点,但有不同的推理。

如果某些内容不是公共 API 的一部分,则可以随时更改

库的作者可以随时更改未“暴露给世界”的内容,而不必发出信号。如果您依赖于仅在库内部使用的东西,您可以通过更新到较新的版本来简单地破坏您的代码。内部代码可以在版本之间更改。

最糟糕的是,你不会知道你的代码会失败,直到它到达在运行时使用反射的部分。编译会成功,没有任何问题。

3. 仅供偶尔使用。

就性能而言:反射使用的范围可以从稍微昂贵holy-crap-what-is-happening-with-my-device-costly

如果使用反射,总会有一些性能开销。即使您认为现代 VM 在最小化问题方面做得更好,它们也不会缓解它。他们只是让它不那么痛苦。

如果您的代码需要偶尔运行,考虑反射是可以的。只是时不时地。不是每秒 7124 次。

4. 除非你不能以任何其他方式做到这一点。

一般来说:

如果你能以“常规的 Java 方式”做某事,就不要使用反射。这不值得。

首先,常规方式会简单得多。其次,使用反射很容易出错(例如,您必须高度依赖"Strings")。

为了帮助你更好地理解我的意思,下面是以“常规 Java 方式”调用的简单方法:

image.png

这是使用反射的同一件事:

image.png

虽然这是一个微不足道的例子,但它已经说明了很多问题。

  1. 您想使用 Java 反射做的任何事情都需要大量代码。
  2. 如果someMethod名称更改,您的代码将不会失败,直到您运行它。编译将成功(请参阅:“公共 API 之外的任何内容都是禁区”部分)。

如果你有适合你周围工作的工具,你就去使用它们。无需打造您自己的工具。

对于非常小比例的超级专业案例,Java 反射可能是需要考虑的东西(例如,请参阅Reflection Bridge与生成的代码进行通信的方法)。这些通常是从头开始设计的,考虑到 Java 反射。

老实说,即使您正在考虑 Java 反射是否适合您的情况,也可能有更好的方法。

5. 任何反射用法都必须经过严格测试。

如果你分析了前面的所有要点并且仍然相信 Java 反射是您的正确选择,那么您需要记住:

任何 Java 反射的使用都必须包含在测试中。