1. Conditional judgment instruction

instruction mnemonics meaning
0x99 ifeq Check if == 0
0x9a ifne Judge whether or not! = 0
0x9b iflt Check if it is less than 0
0x9c ifge Check whether the value is greater than or equal to 0
0x9d ifgt Check whether the value is greater than 0
0x9e ifle Check if <= 0
0x9f if_icmpeq Whether two ints ==
0xa0 if_icmpne Two int yes! =
0xa1 if_icmplt Are two ints <
0xa2 if_icmpge Whether two ints >=
0xa3 if_icmpgt Two int is >
0xa4 if_icmple Whether two ints <=
0xa5 if_acmpeq Whether two references ==
0xa6 if_acmpne Two references if! =
0xc6 ifnull Check whether == null
0xc7 ifnonnull Judge whether or not! = null

A few notes:

  • Byte, short, and char are all compared as ints because operand stacks are all 4 bytes
  • Goto The bytecode used to jump to the specified line number

Case source:

public class Demo3_3 {
	public static void main(String[] args) {
		int a = 0;
			if(a == 0) {
				a = 10;
			} else {
				a = 20; }}}Copy the code

Byte code:

0: iconst_0
1: istore_1
2: iload_1
3: ifne 		12
6: bipush 		10
8: istore_1
9: goto 		15
12: bipush 		20
14: istore_1
15: return
Copy the code

Long, float, double, float, float, float, float Reference docs.oracle.com/javase/spec…

2. Cycle control instruction

In fact, the loop control is the same as the previous instructions, such as the while loop:

public class Demo3_4 {
	public static void main(String[] args) {
		int a = 0;
		while (a < 10) { a++; }}}Copy the code

The bytecode is:

0: iconst_0
1: istore_1
2: iload_1
3: bipush 		10
5: if_icmpge 	14
8: iinc 		1.1
11: goto 		2
14: return
Copy the code

Or the do while loop:

public class Demo3_5 {
	public static void main(String[] args) {
		int a = 0;
		do {
			a++;
		} while (a < 10); }}Copy the code

The bytecode is:

0: iconst_0 
1: istore_1 
2: iinc 1.1 
5: iload_1 
6: bipush 10 
8: if_icmplt 2 
11: return
Copy the code

Finally, look at the for loop:


public class Demo3_6 {
	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
		}
	}
}
Copy the code

The bytecode is:


0: iconst_0
1: istore_1
2: iload_1
3: bipush 		10
5: if_icmpge 	14
8: iinc 		1.1
11: goto 		2
14: retur
Copy the code

Note: comparing the bytecodes of while and for, you can see that they are identical and that the different paths can go the same way

Practice – Judge the results

In bytecode terms, the following code runs:


public class Demo3_6_1 {
	public static void main(String[] args) {
		int i = 0;
		int x = 0;
		while (i < 10) {
			x = x++;
			i++;
		}
		System.out.println(x); // The result is 0}}Copy the code

4. Construction method

Constructor of class < cinit>()V

public class Demo3_8_1 {
	static int i = 10;
	static {
		i = 20;
	}
	static {
		i = 30; }}Copy the code

The compiler collects all static code blocks and static member assignments from top to bottom and merges them into a special method < cinit>()V:

0: bipush 		10  // I = 10
2: putstatic 	#2 	// Field i:I
5: bipush 		20	
7: putstatic 	#2 	// Field i:I
10: bipush 		30
12: putstatic 	#2 	// Field i:I
15: return
Copy the code

The < cinit>()V method is called during the initialization phase of the class load

The final result of this code is 30!

Exercise: students can adjust the position of static variables and static code blocks themselves and observe bytecode changes

< init>()V Instance object constructor

public class Demo3_8_2 {
	private String a = "s1";
	{
		b = 20;
	}
	private int b = 10;
	{
		a = "s2";
	}
	public Demo3_8_2(String a, int b) {
		this.a = a;
		this.b = b;
	}
	public static void main(String[] args) {
		Demo3_8_2 d = new Demo3_8_2("s3".30);
		System.out.println(d.a);// s3
		System.out.println(d.b);/ / 30}}Copy the code

The compiler collects all {} code blocks and member variable assignments from top to bottom to form a new constructor, but the code inside the original constructor is always last:

public cn.itcast.jvm.t3.bytecode.Demo3_8_2(java.lang.String, int); descriptor: (Ljava/lang/String; I)V flags: ACC_PUBLIC Code: stack=2, locals=3, args_size=3
			0: aload_0
			1: invokespecial 	#1 	// super.<init>()V
			4: aload_0
			5: ldc 				#2  // <- "s1"
			7: putfield 		#3 	// -> this.a
			10: aload_0
			11: bipush 			20  / / < - 20
			13: putfield 		#4  // -> this.b
			16: aload_0
			17: bipush 			10  / / < - 10
			19: putfield 		#4  // -> this.b
			22: aload_0
			23: ldc 			#5  // <- "s2"
			25: putfield 		#3  // -> this.a
			28: aload_0 			// ------------------------------
			29: aload_1 			// <- slot 1(a) "s3" |
			30: putfield 		#3  // -> this.a |
			33: aload_0 											|
			34: iload_2 			// <- slot 2(b) 30 |
			35: putfield 		#4  // -> this.b --------------------
			38: return
		LineNumberTable: ...
		LocalVariableTable:
			Start Length Slot Name Signature
				0     39    0 this Lcn/itcast/jvm/t3/bytecode/Demo3_8_2;
				0     39    1    a Ljava/lang/String;
				0     39    2    b         I
		MethodParameters: ...
Copy the code

5. Method calls

Take a look at the bytecode instructions for several different method calls:

public class Demo3_9 {
	public Demo3_9(a) {}private void test1(a) {}private final void test2(a) {}public void test3(a) {}public static void test4(a) {}public static void main(String[] args) {
		Demo3_9 d = newDemo3_9(); d.test1(); d.test2(); d.test3(); d.test4(); Demo3_9.test4(); }}Copy the code

Byte code:

0: new 				#2 // class cn/itcast/jvm/t3/bytecode/Demo3_9
3: dup
4: invokespecial 	#3 // Method "<init>":()V
7: astore_1
8: aload_1
9: invokespecial 	#4 // Method test1:()V
12: aload_1
13: invokespecial 	#5 // Method test2:()V
16: aload_1
17: invokevirtual 	#6 // Method test3:()V
20: aload_1
21: pop
22: invokestatic 	#7 // Method test4:()V
25: invokestatic 	#7 // Method test4:()V
28: return
Copy the code
  • New creates an object, allocates heap memory to the object, and pushes the object reference onto the operand stack.
  • Dup is the content at the top of the assignment operand stack. In this example, it is the object reference. Why do we need two references? ()V (consumes one reference at the top of the stack) and the other is assigned to the local variable in conjunction with astore_1.
  • The final method, private method and constructor are all called by the Invokespecial instruction, which belong to static binding.
  • The ordinary member method is called by Invokevirtual and is dynamically bound, i.e. supports polymorphism.
  • Another difference between a member method and a static method call is whether an object reference is required before the method is executed.
  • More interesting is d.test4(); Call a static method through an object reference. Invokestatic previously executed the pop instruction, dropping the object reference from the operand stack.
  • Another case where invokespecial is executed is when a superclass method is called through super.

6. Principle of polymorphism

/** * -XX:-UseCompressedOops -XX:-UseCompressedClassPointers */
public class Demo3_10 {
	public static void test(Animal animal) {
		animal.eat();
		System.out.println(animal.toString());
	}
	public static void main(String[] args) throws IOException {
		test(new Cat());
		test(newDog()); System.in.read(); }}abstract class Animal {
	public abstract void eat(a);
	@Override
	public String toString(a) {
		return "I am" + this.getClass().getSimpleName(); }}class Dog extends Animal {
	@Override
	public void eat(a) {
		System.out.println("Bone gnawing"); }}class Cat extends Animal {
	@Override
	public void eat(a) {
		System.out.println("Fish"); }}Copy the code

1) Run the code

Stop on the system.in.read () method and run JPS to get the process ID

2) Run the HSDB tool, go to the JDK installation directory, and run:

java -cp ./lib/sa-jdi.jar sun.jvm.hotspot.HSDB
Copy the code

Attach the process ID to the GUI and open Tools -> Find Object By Query:

Input the select d from cn. Itcast. The JVM. T3. The bytecode. Dog d click Execute



4) View the object memory structure

Click on the hyperlink to see the memory structure of the object, which has no attributes, so only 16 bytes of the object header, with the first 8 bytes being

MarkWord, the last 8 bytes are the Class pointer to the object, but its actual address is not currently visible



You can use Windows -> Console to enter the CLI mode and run

mem 0x00000001299b4978 2
Copy the code

Mem takes two arguments: argument 1 is the address of the object and argument 2 is the view of 2 lines (16 bytes)

The second line 0x000000001b7d4028 is the memory address of Class



6) View the class vtable

  • Method 1: Enter the Inspector with Alt+R and type in the memory address of the Class

  • Method 2: or Tools -> Class Browser type Dog search to get the same result



Either way, you can find that the vtable of the Dog Class has a length of 6, meaning that the Dog Class has 6 virtual methods (polymorphic, final, static are not included).

So who are these six methods? Start from the start address of Class. Offset 0x1b8 is the start address of vtable.

0x000000001b7d4028
1b8 +
---------------------
0x000000001b7d41e0
Copy the code

On Windows -> Console, go to the CLI and run

mem 0x000000001b7d41e0 6
0x000000001b7d41e0: 0x000000001b3d1b10
0x000000001b7d41e8: 0x000000001b3d15e8
0x000000001b7d41f0: 0x000000001b7d35e8
0x000000001b7d41f8: 0x000000001b3d1540
0x000000001b7d4200: 0x000000001b3d1678
0x000000001b7d4208: 0x000000001b7d3fa8
Copy the code

You get the entry addresses of the six virtual methods

7) Verify method address

Use Tools -> Class Browser to view the method definitions of each Class

Dog - public void eat(a) @0x000000001b7d3fa8
Animal - public java.lang.String toString(a) @0x000000001b7d35e8;
Object - protected void finalize(a) @0x000000001b3d1b10;
Object - public boolean equals(java.lang.Object) @0x000000001b3d15e8;
Object - public native int hashCode(a) @0x000000001b3d1540;
Object - protected native java.lang.Object clone(a) @0x000000001b3d1678;
Copy the code

Sit down and find out

  • The eat() method is Dog’s own

8) summary

When executing invokevirtual instructions:

  1. The object is first found by the object reference in the stack frame.
  2. Analyze the object header to find the actual Class of the object.
  3. The Class structure has the VTable, which is generated at the link stage of the Class load based on the method rewrite rules.
  4. Look up the table for the exact address of the method.
  5. Execute the bytecode of the method.