开启掘金成长之旅!这是我参与「掘金日新计划 · 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 方式”调用的简单方法:
这是使用反射的同一件事:
虽然这是一个微不足道的例子,但它已经说明了很多问题。
- 您想使用 Java 反射做的任何事情都需要大量代码。
- 如果
someMethod名称更改,您的代码将不会失败,直到您运行它。编译将成功(请参阅:“公共 API 之外的任何内容都是禁区”部分)。
如果你有适合你周围工作的工具,你就去使用它们。无需打造您自己的工具。
对于非常小比例的超级专业案例,Java 反射可能是需要考虑的东西(例如,请参阅Reflection Bridge与生成的代码进行通信的方法)。这些通常是从头开始设计的,考虑到 Java 反射。
老实说,即使您正在考虑 Java 反射是否适合您的情况,也可能有更好的方法。
5. 任何反射用法都必须经过严格测试。
如果你分析了前面的所有要点并且仍然相信 Java 反射是您的正确选择,那么您需要记住:
任何 Java 反射的使用都必须包含在测试中。