The JVM basically simulates a CPU for a Java program. Just as a CPU executes assembled opcodes natively on the hardware, the JVM executes Java opcodes, but strictly in software.
What does this exactly mean? is the bytecodes are ISA for JVM and JVM
in-turn support ISA of processors.
An ISA (Instruction Set Architecture) specifies the entire set of disciplines and techniques that apply to writing low-level software that runs directly on the CPU. It includes a set of opcodes, which are uncomposable direct CPU commands. The JVM recognizes its own set of bytecodes (i.e. 8-bit opcodes) that direct the JVM to carry out interpreter-primitive instructions. So, yes, the bytecode specification makes up part of the JVM's ISA.
The JVM iterates through the list of opcodes executing them one by one using its own memory
to emulate hardware components (e.g. stack, register, main memory) and using primitive arithmetic and logic operations to emulate the ALU. These emulated components also make up the JVM's ISA. This is the basic construction of any interpreter, give or take. However, to improve the runtime of Java applications, the JVM compiles "hotspots" to machine-specific code for optimal performance. Hotspots are sections of the code that are ran frequently. This is known as "Just-In-Time" compilation, and can be done while the program is executing. This technique brings Java's performance a lot closer to that of compiled languages. JIT is used in the .NET framework as well.
Each operating system has its own JVM implementation, which may also vary by the device's ISA. For example, you may have a JVM written for Linux-Arm, Linux-x86, or Windows-x86. The JVM itself may be written in a platform-independent (sort of anyway) language like C, but its JIT compiler must support compilation to the device's instruction set.