The Java virtual machine is becoming ubiquitous. Originally it was found primarily in web browsers to support animated web pages. Now it is found inside databases, personal portable computers, smart cards, and cellular phones. Most popular operating systems come with an implementation of the JVM; if they don't, they will soon.
Because there are so many JVMs in place, the native part of the Java platform will gradually settle so that you don't have to replace your JVM implementation. Platform changes will still occur as new functionality is added, but this will increasingly come in the form of new Java class libraries. You can deliver these with your software to any JVM, which will make the Java slogan "Write Once, Run Anywhere" more true than ever.
As the JVM becomes more common, new languages besides Java will be required. There are many reasons for creating new languages. Sometimes things that are hard in one language are easy in another. If you write Perl, then you know that it's better than Java for processing streams of text; it's great for writing CGI scripts. Eiffel is great for large projects where you need to enforce contracts between programmers. Other languages encourage other features: parallel processing (Occam), symbol manipulation (Lisp), algebra (Maple and Mathematica).
Rather than pile all these features into Java, these and other languages may be implemented for the existing Java virtual machine. This allows programmers the best of both worlds: the ubiquity of the JVM and the features of a favorite language.
Another thing that will happen to JVMs is that they will get faster. The first JVM implementations worked as an interpreter, reading each instruction and calling an appropriate function to perform the operation. Newer JVMs work by first translating an entire method into native code, then executing the native code. This imposes a small burden at the beginning, but this burden is quickly lifted by the elimination of the need to translate each instruction one at a time.
The translation into native code will provide other benefits. Modern processors are extremely good at taking maximum advantage of their available power. For example, if one instruction adds the variables a and b and the next instruction multiplies the variables c and d, then why not execute both simultaneously? They use different parts of the CPU and different parts of memory. This lets you do the work in half the time. Designing your translator to take advantage of this requires careful study and planning, but the potential performance improvements are huge.
Similarly, targeting your compilation to a particular processor (like the 80486) means that you may miss out on optimizations made by other processors (like the Pentium). If you compiled just for the Pentium, then your program may not run on an 80486. You could build and ship two different versions, which will make your marketing department increasingly cranky. Expect future JVM implementations to do a good job at targeting native code generation to precisely the processor on which it is running for another performance boost.
These changes help bring Java closer to the performance of C or C++. Performance improves further when the JVM runtime system is able to make optimizations impossible in C and C++. In these lower-level languages, where memory is just a huge set of bytes, it is sometimes difficult to recognize when one pointer "shadows" another that is, when the two pointers point to the same place. This can make it hard to optimize.
A piece of code might appear to write into a memory location that is never read, which means that you can eliminate the calculation. If there's a shadow pointer in some other section of code, then you may not make this optimization. In the JVM it's easier than in C to detect shadowing, which will allow this optimization to be made more often. This is only one example; the abstract nature of the JVM allows for much better translations than the bits-and-bytes thinking of C and C++.
Finally, who said that the translation from JVM bytecodes into native code has to happen only once? Often, optimizations are made based on guesses of what is going to happen. You have a limited number of fast registers; once you have used them up, other values must be placed in slower memory. You want to place the most-used values in registers, but sometimes it's hard to tell. The JVM can take its best guess, just like a C compiler, but the JVM has the option of watching what's going on and then changing the code if it guessed wrong, which a C compiler can never do. JVM implementations will be blazingly fast, probably sooner than you expect.