Interpreting byte code basically reads the bytecode line by line, doing no optimization or anything, and parsing it and executing it in realtime. This is notably inefficient for a number of reasons, including the issue that Java bytecode isn't designed to be interpreted quickly.
When a method is compiled, the JIT loads the whole method and generates native code to run directly on the CPU, rather than reading and interpreting the byte code line by line. After the method is compiled once, the generated native code gets used directly every time the method is called. This is astronomically faster, but incurs some overhead when the method gets compiled; among other things, the JVM is responsible for only compiling frequently called methods, to minimize the overhead while maximizing the performance of "tight inner loop" code that gets called extremely often.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…