我最近开始制作简单的 2D 游戏,遇到了一个难题 - 使用或不使用 getter 和 setter 方法来获取对象的 x 和 y 位置。如果我不使用方法,而是直接访问变量,它看起来会更清晰,而且,对对象的许多方法调用会损害性能。获取和设置位置也很简单,所以这里真的不需要封装吗?还是我们应该始终遵守 getter 和 setter 方法的约定?
4 回答
遵守约定总是更好。此外,JIT 将简化操作,以便直接访问该字段,而不是遍历所有方法堆栈。
它被称为方法内联。
Java VM 的 Java 2 版本在运行时自动内联简单方法。在未优化的 Java VM 中,每次调用新方法时,都会创建一个新的堆栈帧。创建新的堆栈帧需要额外的资源以及堆栈的一些重新映射,最终结果是创建新的堆栈帧会产生很小的开销。
方法内联通过减少程序进行的方法调用次数来提高性能。Java VM 内联代码内联返回常量或仅访问内部字段的方法。
资源 :
在同一主题上:
你不应该有 getter 和 setter,也不应该公开属性。
相反,您可以使用 .updatePosition()、.draw()、.moveTo()、.collideWith() 等方法,因此您无需直接从外部获取或设置值。
在极少数情况下,您真的想直接从外部获取/设置值,但这些情况很少见,而且往往表明设计不佳(尽管有有效的用途)。
我会使用getter/setter。为什么 ?
- 封装是关键。也许您稍后会更改存储位置的方式(例如,笛卡尔到极坐标?)。Getter/setter 将允许您执行适当的转换。
- 设置器将允许您的对象强制执行条件(例如 x > 0 和 < 10 ?)
另一个原因(尽管目前可能不适合您的需求)是许多 Java 框架使用反射和内省类来使用传统setX
/getX
格式的 setter/getter。通过实现这些方法,您的类可以立即在各种框架中重用。
在已知问题之前不要担心性能。过早的优化会给你带来太多的麻烦。
在Stendhal中,我们确实使用了 getter/setter。我们每回合处理大约 60,000 个可移动对象。根据我在 Stendhal 的经验,简单的方法根本没有任何可衡量的性能影响。我们进行了一些分析以发现各种问题,并在过去几个月中大大提高了性能。
我们遇到的主要瓶颈是路径查找(尤其是与其他可移动物体的碰撞检测)。存在这样的问题,例如在每次可能的碰撞检查时创建一个新的 Pair 对象,或者在询问实体的位置和大小时创建一个新的 Rectangle 对象。
这些东西很容易在 Profiler 中发现(请参阅在 gamedev 上的 java 中的 Profiling server side game loop)。
游戏循环逻辑部分之外的其他常见延迟原因是客户端/服务器通信和数据库访问。