I think the question is poorly structured but there's still a value trying to answer it.
I can see your confusion and the problem is that the real mechanics of Java Interpreter are actually quite different from what you may imagine when you just read a high-level description of an interpreter.
To start with, Java (or another JVM-based language) source code is compiled into bytecode via javac. This produces a relatively simple .class file format which may contain ~200 bytecodes - this isn't a format that is directly executable by any real computer; rather it's a format designed to be executed by a "virtual machine", that is the JVM.
Therefore, to be able to execute compiled java programs on real machines we need to "convert" them into an executable representation, that is machine code (the same thing as native code).
By default, the JVM acts as an interpreter: that means the .class files are read and executed one bytecode (opcode) at a time.
The role of the interpreter is to read the opcode and execute a corresponding action - this is where it gets more complicated...
Normally, you'd expect that the interpreter would have a big switch statement covering all possible opcodes and executing appropriate actions based on the bytecode it encounters like:
switch (opcode) {
case iconst_1: handleIConst1();
...
}
This code would be part of the interpreter (that is the JVM itself) and would be compiled to the machine code ahead of time - you get this when you install an OS-specific version of JVM/JDK.
However, the JVM interpreter is a special type called Template Interpreter.
It doesn't contain a hardcoded logic but actually maintains a table of mappings between opcodes and machine code. This table is populated when the JVM is starting (you can see it via -XX:+PrintInterpreter
-> requires the hsdis
library).
Later on, when JVM starts interpreting bytecodes the interpreter will check in the table whether it has a corresponding entry to the code cache where the machine code resides. If so, then it executes the machine code directly; otherwise it can fallback to resolving the bytecode dynamically.
So we have the interpreter which executes bytecodes one-by-one.
Moreover, there's also JIT which is used if some method is "hot enough" (called thousands of times). The JIT will kick in and takes place of the interpreter - it will compile the whole method into native code which is then executed on the target machine.
Finally, the issue of system calls is unrelated to this matter. System calls have to be used by any program that wants to access hardware or other sensitive resources. They are not part of your program, rather they are provided by the OS.
Resources