Why is the number of local variables used in a Java bytecode method not the most economical?
There are several reasons. First off, it's not necessary for performance. The JVM already optimizes things at runtime, so there's no point in adding redundant complexity to the compiler.
However, another major reason noone has mentioned here is debugging. Making the bytecode as close to the original source as possible makes it a lot easier to debug.
Simply because Java gains performance from the just-in-time compiler.
What you do in Java source, and even what shows up in the class files isn't what enables performance at runtime. Of course you shouldn't neglect that part, but only in the sense of not making "stupid mistakes".
Meaning: the jvm decides at runtime if a method is worth translating into (highly optimized!) machine code. If the jvm decides "not worth optimising", why make javac more complex and slower by having a lot of optimization in there? Plus: the more simple and basic the incoming byte code, the easier it is for the JIT to analyze and improve that input!
Well, you did just make a false dependency between what used to be two completely separate locals. This would mean that the JIT compiler either needs to be more complex/slower to unravel the change and get back to the original bytecode anyway, or would be restricted in the kind of optimizations it can do.
Keep in mind that the Java compiler runs once, on your development (or build) machine. It's the JIT compiler that knows the hardware (and software) it's running on. The Java compiler needs to create simple, straight-forward code that is easy for the JIT to process, and optimize (or, in some cases, interpret). There's very little reason to excessively optimize the bytecode itself - you might shave off a few bytes off the executable size, but why bother, especially if the result would be either less CPU efficient code or longer JIT compilation time?
I don't have the environment to do an actual test right now, but I'm pretty sure the JIT will produce the same executable code from the two bytecodes (it certainly does in .NET, which is in many ways similar).