问题描述
现代的JVM / JIC编译器已消除了大多数传统的“慢速”操作对性能的影响,这些操作包括instanceof,异常处理,反射等。
正如Donald Knuth所说:“我们应该忘记效率低下的问题,大约有97%的时间是这样:过早的优化是万恶之源。” instanceof的性能可能不会成为问题,因此在确定这是问题之前,请不要浪费时间来寻求新的解决方法。
我编写了一个基准程序来评估不同的实现:
-
instanceof
实施(作为参考) - 通过抽象类和@Override测试方法定位的对象
- 使用自己的类型实现
-
getClass() == _.class
实作
我使用jmh进行了100次预热调用,正在测量的1000次迭代以及10次fork来运行基准测试。因此,每个选项的测量结果均为1万次,这需要12:18:57才能在具有macOS 10.12.4和Java 1.8的MacBook Pro上运行整个基准测试。基准衡量每个选项的平均时间。有关更多详细信息,请参见我在GitHub上的实现。
为了完整起见:该答案有一个较早的版本和我的基准。
结果
Operation | Runtime in nanoseconds per operation | Relative to instanceof |
---|---|---|
INSTANCEOF | 39,598 ± 0,022 ns/op | 100,00 % |
GETCLASS | 39,687 ± 0,021 ns/op | 100,22 % |
TYPE | 46,295 ± 0,026 ns/op | 116,91 % |
OO | 48,078 ± 0,026 ns/op | 121,42 % |
tl; dr
instanceof
尽管getClass()
非常接近,但在Java 1.8中是最快的方法。
解决方法
我正在开发一个应用程序,一种设计方法涉及大量使用instanceof
操作员。虽然我知道OO设计通常会尝试避免使用instanceof
,但这是另一回事了,这个问题与性能完全相关。我想知道是否会对性能产生影响?是一样快==
吗?
例如,我有一个包含10个子类的基类。在采用基类的单个函数中,我检查该类是否是子类的实例并执行一些例程。
我想解决的另一种方法是改用“类型ID”整数基元,并使用位掩码表示子类的类别,然后将子类“类型ID”与位掩码进行位掩码比较。代表类别的常量掩码。
instanceof JVM
是否以某种方式对其进行了优化,使其速度更快?我想坚持使用Java,但应用程序的性能至关重要。如果以前曾走过这条路的人可以提供一些建议,那将很酷。我是否挑剔或专注于错误的东西进行优化?