The Wrong Abstraction
Another thing that’s slow in Java is array accesses. Let’s look at arrays for a second. An array is nothing more than a blob of memory with fixed-size elements. This is actually a very low-level construct. Arrays in Java try to mimic a low-level concept with high-level semantics. This is fairly obviously a bad idea.
Unlike arrays in C, arrays in Java are bound-checked. Every time you access an element in the array, you have to check that the index is in-bounds, and then perform the access. A slightly higher-level abstraction could allow much more of this bounds-checking to be done at compile time. Some research at IBM uses set theoretical concepts to do this, and provides a significant performance boost. The problem, isn’t that Java is a high-level language; it’s that it chose the wrong abstractions.
Other data structures work significantly better in high-level languages. A dictionary or associative array, for example, can be implemented transparently by a tree or a hash table (or some combination of the two) in a high-level language; the runtime can even decide which, based on the amount and type of data fed to it. This kind of dynamic optimization is simply impossible in a low-level language without building higher-level semantics on top and meta-programming—at which point, you would be better off simply selecting a high-level language and letting someone else do the optimization.