The Development cycle of a Java application consists of compilation, download, interpretation, and execution.
Java compilers translate Java source programs into JVM executable code – bytecode. This compilation process is somewhat different from C/C++ compilation. When a C compiler compiles code that generates an object, the code is created to run on a particular hardware platform. Therefore, during compilation, the compiler converts all references to symbols to specific memory offsets by looking up tables to keep the program running. Instead of compiling references to variables and methods into numeric references, the Java compiler does not determine the memory layout during program execution. Instead, the symbolic reference information is kept in the bytecode, which the interpreter creates at run time, and then looks up tables to determine the address of a method. This effectively ensures the portability and security of Java.
The job of running the JVM bytecode is done by the interpreter. The explanation execution process is divided into three parts: code loading, code verification and code execution. Loading code is done by a class loader. The classloader is responsible for loading all the code needed to run a program, including the classes that the classes in the program code inherit from and the classes that it calls. When a class loader loads a class, the class is placed in its own namespace. There is no other way that classes can influence each other other than by referring to their own namespaces through symbols. All classes on this computer are in the same address space, and all classes imported from outside have their own separate namespace. This allows native classes to run efficiently by sharing the same namespace, while ensuring that they do not interact with imported classes. When all the classes needed to run the program are loaded, the interpreter determines the memory layout of the entire executable program. The interpreter establishes mappings and lookup tables for symbolic references to specific address Spaces. By determining the memory layout of the code at this stage, Java takes care of the problem of superclass changes causing subclasses to crash, while also preventing code from accessing addresses illegally. The loaded code is then checked by a bytecode validator. The verifier can detect errors such as operand stack overflow, illegal data type conversion, and so on. Once verified, the code is executed.
Java bytecode can be executed in two ways:
1. Just-in-time compilation: the interpreter first compiles the bytecode to machine code and then executes the machine code.
2. Explain execution: The interpreter performs all operations on the Java bytecode sequence by interpreting and executing a small piece of code at a time.
The second method is usually used. The flexibility of the JVM specification makes it efficient to translate byte code into machine code. For those applications with high speed requirements, the interpreter can compile Java bytecode into machine code on the fly, thus ensuring the portability and high performance of Java code.