Bytecode is the set of instructions used by the JVM. To illustrate this let’s take this Hello World program.

public static void main(String[] args){
    System.out.println("Hello World");
}

This is what it turns into when compiled into bytecode.

public static main([Ljava/lang/String; args)V    
    getstatic java/lang/System out Ljava/io/PrintStream;
    ldc "Hello World"
    invokevirtual java/io/PrintStream print(Ljava/lang/String;)V

What’s the logic behind this?

getstatic - Retreives the value of a static field of a class. In this case, the PrintStream “Out” of System.

ldc - Push a constant onto the stack. In this case, the String “Hello World”

invokevirtual - Invokes a method on a loaded reference on the stack and puts the result on the stack. Parameters of the method are also taken from the stack.

Well, there has to be more right?

There are 255 opcodes, but not all of them are implemented yet. A table with all of the current opcodes can be found here: Java bytecode instruction listings.

How can I write / edit bytecode?

There’s multiple ways to write and edit bytecode. You can use a compiler, use a library, or use a program.

For writing:

For editing: