A text read Java bytecode

Foreword

With the continuous development of the Java language, Java application scenarios are slowly expanding variety of elegant problem-solving technique has also been derived, such as AOP technology, a clear understanding of the Java Runtime principle becomes necessary, the focus of this article to explain Java bytecode knowledge.

Base bytecodes

Java files generated by the compiler class bytecode files, bytecode file also has its own file format, not to proceed here in detail, look directly through Java tools to bring their own. First, we test class file as follows:

public class Person {

	public String name;
	public int age;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}
复制代码

Defines a Person class, which has the properties name and age, the compiler generates Person.class file directly using the Java class file this tool dump, dump command is as follows:

javap -v -p Person.class
复制代码

dump generated as follows:

public class com.sec.resourceparse.Person
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #5.#27         // java/lang/Object."<init>":()V
   #2 = Fieldref           #4.#28         // com/sec/resourceparse/Person.name:Ljava/lang/String;
   #3 = Fieldref           #4.#29         // com/sec/resourceparse/Person.age:I
   #4 = Class              #30            // com/sec/resourceparse/Person
   #5 = Class              #31            // java/lang/Object
   #6 = Utf8               name
   #7 = Utf8               Ljava/lang/String;
   #8 = Utf8               age
   #9 = Utf8               I
  #10 = Utf8               <init>
  #11 = Utf8               ()V
  #12 = Utf8               Code
  #13 = Utf8               LineNumberTable
  #14 = Utf8               LocalVariableTable
  #15 = Utf8               this
  #16 = Utf8               Lcom/sec/resourceparse/Person;
  #17 = Utf8               getName
  #18 = Utf8               ()Ljava/lang/String;
  #19 = Utf8               setName
  #20 = Utf8               (Ljava/lang/String;)V
  #21 = Utf8               getAge
  #22 = Utf8               ()I
  #23 = Utf8               setAge
  #24 = Utf8               (I)V
  #25 = Utf8               SourceFile
  #26 = Utf8               Person.java
  #27 = NameAndType        #10:#11        // "<init>":()V
  #28 = NameAndType        #6:#7          // name:Ljava/lang/String;
  #29 = NameAndType        #8:#9          // age:I
  #30 = Utf8               com/sec/resourceparse/Person
  #31 = Utf8               java/lang/Object
{
  public java.lang.String name;
    descriptor: Ljava/lang/String;
    flags: ACC_PUBLIC

  public int age;
    descriptor: I
    flags: ACC_PUBLIC

  public com.sec.resourceparse.Person();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/sec/resourceparse/Person;

  public java.lang.String getName();
    descriptor: ()Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #2                  // Field name:Ljava/lang/String;
         4: areturn
      LineNumberTable:
        line 9: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/sec/resourceparse/Person;

  public void setName(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: putfield      #2                  // Field name:Ljava/lang/String;
         5: return
      LineNumberTable:
        line 13: 0
        line 14: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0  this   Lcom/sec/resourceparse/Person;
            0       6     1  name   Ljava/lang/String;
复制代码

Here intercepted part, briefly look at first is the introduction of such information:

public class com.sec.resourceparse.Person
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
复制代码

Class names, JDK version of the compiler, as well as access modifier
then the string pool:

Constant pool:
   #1 = Methodref          #5.#27         // java/lang/Object."<init>":()V
   #2 = Fieldref           #4.#28         // com/sec/resourceparse/Person.name:Ljava/lang/String;
   #3 = Fieldref           #4.#29         // com/sec/resourceparse/Person.age:I
   #4 = Class              #30            // com/sec/resourceparse/Person
   #5 = Class              #31            // java/lang/Object
   #6 = Utf8               name
   #7 = Utf8               Ljava/lang/String;
复制代码

Here the entire class containing the string inside, contains a declaration of the class information, attribute, etc.
Finally, the method of information:

 public java.lang.String getName();
    descriptor: ()Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #2                  // Field name:Ljava/lang/String;
         4: areturn
      LineNumberTable:
        line 9: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/sec/resourceparse/Person;
复制代码

Here is the main method name, access modifiers, flow of information and operational execution stack
after reading the entire class of class files, here are the basics of the bytecode related.

Access modifier

Above the bytecode classes, properties, and methods in both flag information, this is the modifier, and the corresponding value in the access modifiers bytecode classes are as follows:

Identifier name Identifier value DEFINITIONS
ACC_PUBLIC 0x0001 Public Type
ACC_FINAL 0x0010 Final type
ACC_SUPER 0x0020 Allow the use of new bytecode instructions invokespecial semantics
ACC_INTERFACE 0x0200 Interface Modifier
ACC_ABSTRACT 0x0400 abstract modifier
ACC_SYNTHETIC 0x1000 This flag is not generated by user code class
ACC_ANNOTATION 0x2000 Notes modifier
**ACC_ENUM 0x400 Enum modifier

Described above is a class access modifier, it is also similar to the properties, and methods, but is relatively simple, here is not to continue the.

Type table

In JAVA basic types, arrays, and an object, the bytecode differentiated type of said table as follows:

Types of Bytecode representation DEFINITIONS
byte B byte
boolean WITH bool
char C character
short S Short integer
int I Integer
float F Float
long J Long integer
double D Float
void V Null return value
class Ljava / lang / Object; Object Types
Array [] [

Wherein category begins with L, middle class path, and finally ends with; the above array is a single array, be used in conjunction with other types, such as int [] bytecode is [the I, int [] [] Word section code is [[I.

Analytical method

Access modifier has been described above, and JAVA byte code type controls, the following explanation about the analysis method, for example take the above method, as follows:

public java.lang.String getName();
    descriptor: ()Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #2                  // Field name:Ljava/lang/String;
         4: areturn
      LineNumberTable:
        line 9: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/sec/resourceparse/Person;
复制代码
  • descriptor: The method described is a method described parameters and return type, the format: (parameter type) return type, there is no representation of the reference value and back String
  • flags: a method of access modifiers, shown here as Public
  • Code: specific methods described in the stack
  • stack: stack allocation maximum depth
  • The number of local variables within the method: locals
  • args_size: Method Number of parameters
  • LineNumberTable: Methods of rows of information (not concerned, did not look)
  • LocalVariableTable: the local variable table

Here briefly explain, class methods At least one parameter, the parameter is the class object itself, the equivalent of this keyword, and the subscript is zero.

Bytecode instruction

As already covered the basics bytecode related, but did not elaborate bytecode instructions related content, this section will focus on the content of bytecode instructions, bytecode instructions are divided into the following categories:

  • Storing the load type instruction
    is loaded into the stack operation parameters or the data stored in the operand stack into local variables, a series of instructions including load, etc. Store instructions and push
  • Object operation instruction
    target instruction including generating a new object from the object property acquiring operations, such as well getStatic putField getField and the like and putStatic
  • Dup and pop stack management instructions such as push and pop instructions to launch
  • Operation instruction
    operation instruction data is mainly addition, subtraction instructions, etc., are performed only in operations where the stack
  • Jump instruction control
    ifelse condition determination instructions and the like, and the like goto
  • Method call and return instructions
    including invoke series of instructions and return instruction series, which invoke a method of instruction execution, return is the return series of instructions

Operation Stack Process

Described above has been completed substantially all of the contents of the byte code, where practical method to explain the operation flow. To remember the following points:
JAVA stack-based method of execution is carried out, the method call instruction after the call stack will be out, if the method returns a value, the value will be returned push

First a simple analysis:

public java.lang.String getName();
    descriptor: ()Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #2                  // Field name:Ljava/lang/String;
         4: areturn
      LineNumberTable:
        line 9: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/sec/resourceparse/Person;
复制代码

1.aload_0: where 0 is the first parameter, push type parameter is the object (front analyzed is this)

2.getfield: attribute name acquired from the current top of the stack object and pressing it onto the stack

3.areturn: the current top of the stack is a value of type String, so the return to the use of use areturn

Re-introduce a little bit more complicated Liezi:

public class Manager {

    public static void main(String [] args) {
        String resPath = "/Users/Desktop/resources.arsc";
        FileInputStream ins = null;
        ByteArrayOutputStream ous = null;
        try {
            ins = new FileInputStream(new File(resPath));
            ous = new ByteArrayOutputStream();
            int length = -1;
            byte data[] = new byte[4 * 1024];
            while ((length = ins.read(data)) != -1) {
                ous.write(data, 0, length);
            }
            byte[] resData = ous.toByteArray();
            ParseUtils.parseRes(resData);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
复制代码

Corresponding to the byte code as follows:

 public com.sec.resourceparse.Manager();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 7: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/sec/resourceparse/Manager;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=5, locals=7, args_size=1
         0: ldc           #2                  // String /Users/Desktop/resources.arsc
         2: astore_1
         3: aconst_null
         4: astore_2
         5: aconst_null
         6: astore_3
         7: new           #3                  // class java/io/FileInputStream
        10: dup
        11: new           #4                  // class java/io/File
        14: dup
        15: aload_1
        16: invokespecial #5                  // Method java/io/File."<init>":(Ljava/lang/String;)V
        19: invokespecial #6                  // Method java/io/FileInputStream."<init>":(Ljava/io/File;)V
        22: astore_2
        23: new           #7                  // class java/io/ByteArrayOutputStream
        26: dup
        27: invokespecial #8                  // Method java/io/ByteArrayOutputStream."<init>":()V
        30: astore_3
        31: iconst_m1
        32: istore        4
        34: sipush        4096
        37: newarray       byte
        39: astore        5
        41: aload_2
        42: aload         5
        44: invokevirtual #9                  // Method java/io/FileInputStream.read:([B)I
        47: dup
        48: istore        4
        50: iconst_m1
        51: if_icmpeq     66
        54: aload_3
        55: aload         5
        57: iconst_0
        58: iload         4
        60: invokevirtual #10                 // Method java/io/ByteArrayOutputStream.write:([BII)V
        63: goto          41
        66: aload_3
        67: invokevirtual #11                 // Method java/io/ByteArrayOutputStream.toByteArray:()[B
        70: astore        6
        72: aload         6
        74: invokestatic  #12                 // Method com/sec/resourceparse/ParseUtils.parseRes:([B)V
        77: goto          87
        80: astore        4
        82: aload         4
        84: invokevirtual #14                 // Method java/lang/Exception.printStackTrace:()V
        87: return

复制代码

The Manager only declares a static main method, but there are ways a bytecode init, in fact, the default constructor with no arguments, look at the byte code of this method:

public com.sec.resourceparse.Manager();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 7: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/sec/resourceparse/Manager;
复制代码

1.aload_0: this object will be pushed onto the stack
2.invokespecial: invoke special methods init stack object method, the type of the return value init V, so after the call stack is empty
3.return: Since there is no stack value, so the return instruction executed directly on it

Re-focus look another way:

public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=5, locals=7, args_size=1
         0: ldc           #2                  // String /Users/Desktop/resources.arsc
         2: astore_1
         3: aconst_null
         4: astore_2
         5: aconst_null
         6: astore_3
         7: new           #3                  // class java/io/FileInputStream
        10: dup
        11: new           #4                  // class java/io/File
        14: dup
        15: aload_1
        16: invokespecial #5                  // Method java/io/File."<init>":(Ljava/lang/String;)V
        19: invokespecial #6                  // Method java/io/FileInputStream."<init>":(Ljava/io/File;)V
        22: astore_2
        23: new           #7                  // class java/io/ByteArrayOutputStream
        26: dup
        27: invokespecial #8                  // Method java/io/ByteArrayOutputStream."<init>":()V
        30: astore_3
        31: iconst_m1
        32: istore        4
        34: sipush        4096
        37: newarray       byte
        39: astore        5
        41: aload_2
        42: aload         5
        44: invokevirtual #9                  // Method java/io/FileInputStream.read:([B)I
        47: dup
        48: istore        4
        50: iconst_m1
        51: if_icmpeq     66
        54: aload_3
        55: aload         5
        57: iconst_0
        58: iload         4
        60: invokevirtual #10                 // Method java/io/ByteArrayOutputStream.write:([BII)V
        63: goto          41
        66: aload_3
        67: invokevirtual #11                 // Method java/io/ByteArrayOutputStream.toByteArray:()[B
        70: astore        6
        72: aload         6
        74: invokestatic  #12                 // Method com/sec/resourceparse/ParseUtils.parseRes:([B)V
        77: goto          87
        80: astore        4
        82: aload         4
        84: invokevirtual #14                 // Method java/lang/Exception.printStackTrace:()V
        87: return
复制代码

Method explanation:

  1. ([Ljava / lang / String;) V: String parameter is a one-dimensional array, no return value
  2. flags: access modifier for the static and the public

Stack operation Explanation:
0: Object push type String, value: "/ Users / Desktop / resources.arsc "

2-6:

  1. Pop the top element 1 and the presence of local variables
  2. The null onto the stack
  3. Pop the top element null, and the presence of local variable 2
  4. The null onto the stack
  5. Pop the top element null, and there is a local variable. 3

After completion of the above operation, the stack and local variables methods are as follows:

7-30:

  1. a new java / io / FileInputStream objects, and pushed onto the stack
  2. dup: The above object is generated and then pushed onto the stack, there are two current stack of objects FileInputStream
  3. a new java / io / File objects, and pushed onto the stack
  4. dup: File object would then pushed onto the stack generated in the above, there are two current stack a File object
  5. aload_1: 1 local variables onto the stack, i.e. the value onto the stack String
  6. invokespecial: File calling the init method, parameter is String, no return value
    Description: 5-6 is to create out of the File object, calling its constructor process, there should figure out why after you create the object to be pressed twice the stack
  7. invokespecial: FileInputStream object's method call, the parameters are File, no return value
  8. astore_2: The top element 2 is stored into local variables
  9. a new java / io / ByteArrayOutputStream objects, and pushed onto the stack
  10. dup: The above object is generated and then pushed onto the stack, there are two current stack objects ByteArrayOutputStream
  11. invokespecial: call the init method of ByteArrayOutputStream
  12. The top element stored into local variable 3

31-42

  1. iconst_m1: -1 is pushed onto the stack
  2. istore 4: pop the stack, local variables stored into 4
  3. sipush 4096: 4096 int type the number onto stack
  4. newarray: out of stack, create an array, and pushed onto the stack
  5. astore 5: pop-up element into the stack and local variable 5
  6. aload_2: local variables onto the stack 2
  7. aload 5: The local variables onto the stack 5
  8. invokevirtual: performing FileInputStream read method, the parameter byte array, int return value
  9. dup: Copy the top element, and pushed onto the stack
  10. istore 4: pop the top element and stored in local variables 4
  11. iconst_m1: -1 is pushed onto the stack and then
  12. if_icmpeq 66: Comparison of the stack 2 int number are equal, equal, direct jump to the line 66, is responsible for implementing the following logic

The basic logic of the above analysis thus, this method is relatively long, do not continue down analysis, is the same step

The key process stack operation: All operations are accompanied by the stack push and logic, such as a method call, using the class parameter and the stack is popped, if the method returns a value, the return value of pressure stack.

to sum up

Bytecode knowledge is quite important to understand the bytecode JVM knowledge can clearly understand the operational mechanism, as well as the back of directly operated bytecode AOP basis.

Reference:
segmentfault.com/a/119000000... my.oschina.net/ta8210/blog...

Guess you like

Origin juejin.im/post/5d5fadf56fb9a06b19734262