There is no dedicated bytecode instruction to perform this kind of selector, so if you want to load a local variable based on the contents of another variable, you have to code this operation yourself, e.g.
// pick #1 or #2 based on #0 in [0..1]
0: iload_0
1: ifne 8
4: aload_1
5: goto 9
8: aload_2
9: // value is now on the stack, ready for use
or
// pick #1, #2, or #3 based on #0 in [0..2]
0: iload_0
1: ifne 8
4: aload_1
5: goto 18
8: iload_0
9: iconst_1
10: if_icmpne 17
13: aload_2
14: goto 18
17: aload_3
18: // value is now on the stack, ready for use
or, to have a variant that scales with higher numbers of variables:
// pick #1, #2, or #3 based on #0 in [0..2]
0: iload_0
1: tableswitch { // 0 to 2
0: 28
1: 32
2: 36
default: 36
}
28: aload_1
29: goto 37
32: aload_2
33: goto 37
36: aload_3
37: // value is now on the stack, ready for use
The last variant has been generated with the ASM library and the following helper method, calling it like loadDynamic(…, 0, 1, 3);
/**
* Load variable #(firstChoice + value(#selector))
*/
public static void loadDynamic(
MethodVisitor target, int selector, int firstChoice, int numChoices) {
Label[] labels = new Label[numChoices];
for(int ix = 0; ix < numChoices; ix++) labels[ix] = new Label();
Label end = new Label();
target.visitVarInsn(Opcodes.ILOAD, selector);
target.visitTableSwitchInsn(0, numChoices - 1, labels[numChoices - 1], labels);
target.visitLabel(labels[0]);
target.visitVarInsn(Opcodes.ALOAD, firstChoice);
for(int ix = 1; ix < numChoices; ix++) {
target.visitJumpInsn(Opcodes.GOTO, end);
target.visitLabel(labels[ix]);
target.visitVarInsn(Opcodes.ALOAD, firstChoice + ix);
}
target.visitLabel(end); // choosen value is now on the stack
}
Obviously, array based code using the intrinsic index based access instructions is much simpler and more efficient in most cases.