Java, as a language, can be implemented, like any language, in various ways. This includes full interpretation, bytecode compilation, and native compilation. See Java Language Specification
The VM specification defines how byte code should be loaded and executed. It defines the format of the compiled class and execution semantics, for example. a problem with threads and the so-called "memory model". See Java VM Specification
While orignally intended for sharing, language and virtual machine are separate specifications. You can compile a different language for Java bytecode and run it on top of the JVM. And you can implement the Java language in many ways, especially without a VM, as long as you follow the expected semantics.
Of course, both of them are still connected, and some aspects of Java can be difficult to support without interpreting the bytecode at all, for example. custom ClassLoader that return a bytecode (see ClassLoader.defineClass ). I think that bytecode should be immediately included in native code or maybe not supported at all.
source share