概览
从 Instruction 的角度来说,与 field 相关的 opcode 有 4 个,内容如下:
opcode | mnemonic symbol | opcode | mnemonic symbol | opcode | mnemonic symbol | opcode | mnemonic symbol |
---|---|---|---|---|---|---|---|
178 | getstatic | 179 | putstatic | 180 | getfield | 181 | putfield |
从 ASM 的角度来说,这些 opcode 与 MethodVisitor.visitXxxInsn()
方法对应关系如下:
MethodVisitor.visitFieldInsn()
:getstatic
,putstatic
,getfield
,putfield
.
non-static field
getfield
从 Java 语言的视角,有一个 HelloWorld
类,代码如下:
public class HelloWorld {
public int value;
public void test() {
int i = this.value;
}
}
从 Instruction 的视角来看,方法体对应的内容如下:
$ javap -c sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
public int value;
...
public void test();
Code:
0: aload_0
1: getfield #2 // Field value:I
4: istore_1
5: return
}
从 ASM 的视角来看,方法体对应的内容如下:
methodVisitor.visitCode();
methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitFieldInsn(GETFIELD, "sample/HelloWorld", "value", "I");
methodVisitor.visitVarInsn(ISTORE, 1);
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(1, 2);
methodVisitor.visitEnd();
从 Frame 的视角来看,local variable 和 operand stack 的变化:
// {this} | {}
0000: aload_0 // {this} | {this}
0001: getfield #2 // {this} | {int}
0004: istore_1 // {this, int} | {}
0005: return // {} | {}
从 JVM 规范的角度来看,getfield
指令对应的 Operand Stack 的变化如下:
..., objectref →
..., value
The objectref
, which must be of type reference
, is popped from the operand stack. The value of the referenced field in objectref
is fetched and pushed onto the operand stack.
putfield
从 Java 语言的视角,有一个 HelloWorld
类,代码如下:
public class HelloWorld {
public int value;
public void test() {
this.value = 0;
}
}
从 Instruction 的视角来看,方法体对应的内容如下:
$ javap -c sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
public int value;
...
public void test();
Code:
0: aload_0
1: iconst_0
2: putfield #2 // Field value:I
5: return
}
从 ASM 的视角来看,方法体对应的内容如下:
methodVisitor.visitCode();
methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitInsn(ICONST_0);
methodVisitor.visitFieldInsn(PUTFIELD, "sample/HelloWorld", "value", "I");
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(2, 1);
methodVisitor.visitEnd();
从 Frame 的视角来看,local variable 和 operand stack 的变化:
// {this} | {}
0000: aload_0 // {this} | {this}
0001: iconst_0 // {this} | {this, int}
0002: putfield #2 // {this} | {}
0005: return // {} | {}
从 JVM 规范的角度来看,putfield
指令对应的 Operand Stack 的变化如下:
..., objectref, value →
...
The value
and objectref
are popped from the operand stack. The objectref
must be of type reference
. The value
undergoes value set conversion, resulting in value'
, and the referenced field in objectref
is set to value'
.
- If the field descriptor type is
boolean
,byte
,char
,short
, orint
, then thevalue
must be anint
. - If the field descriptor type is
float
,long
, ordouble
, then thevalue
must be afloat
,long
, ordouble
, respectively. - If the field descriptor type is a
reference
type, then thevalue
must be of a type that is assignment compatible with the field descriptor type. - If the field is
final
, it must be declared in the current class, and the instruction must occur in an instance initialization method (<init>
) of the current class.
static field
getstatic
从 Java 语言的视角,有一个 HelloWorld
类,代码如下:
public class HelloWorld {
public static int staticValue;
public void test() {
int i = HelloWorld.staticValue;
}
}
从 Instruction 的视角来看,方法体对应的内容如下:
$ javap -c sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
public static int staticValue;
...
public void test();
Code:
0: getstatic #2 // Field staticValue:I
3: istore_1
4: return
}
从 ASM 的视角来看,方法体对应的内容如下:
methodVisitor.visitCode();
methodVisitor.visitFieldInsn(GETSTATIC, "sample/HelloWorld", "staticValue", "I");
methodVisitor.visitVarInsn(ISTORE, 1);
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(1, 2);
methodVisitor.visitEnd();
从 Frame 的视角来看,local variable 和 operand stack 的变化:
// {this} | {}
0000: getstatic #2 // {this} | {int}
0003: istore_1 // {this, int} | {}
0004: return // {} | {}
从 JVM 规范的角度来看,getstatic
指令对应的 Operand Stack 的变化如下:
..., →
..., value
The value
of the class or interface field is fetched and pushed onto the operand stack.
putstatic
从 Java 语言的视角,有一个 HelloWorld
类,代码如下:
public class HelloWorld {
public static int staticValue;
public void test() {
HelloWorld.staticValue = 1;
}
}
从 Instruction 的视角来看,方法体对应的内容如下:
$ javap -c sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
public static int staticValue;
...
public void test();
Code:
0: iconst_1
1: putstatic #2 // Field staticValue:I
4: return
}
从 ASM 的视角来看,方法体对应的内容如下:
methodVisitor.visitCode();
methodVisitor.visitInsn(ICONST_1);
methodVisitor.visitFieldInsn(PUTSTATIC, "sample/HelloWorld", "staticValue", "I");
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(1, 1);
methodVisitor.visitEnd();
从 Frame 的视角来看,local variable 和 operand stack 的变化:
// {this} | {}
0000: iconst_1 // {this} | {int}
0001: putstatic #2 // {this} | {}
0004: return // {} | {}
从 JVM 规范的角度来看,putstatic
指令对应的 Operand Stack 的变化如下:
..., value →
...
The value
is popped from the operand stack and undergoes value set conversion, resulting in value'
. The class field is set to value'
.
The type of a value
stored by a putstatic
instruction must be compatible with the descriptor of the referenced field.
- If the field descriptor type is
boolean
,byte
,char
,short
, orint
, then thevalue
must be anint
. - If the field descriptor type is
float
,long
, ordouble
, then thevalue
must be afloat
,long
, ordouble
, respectively. - If the field descriptor type is a
reference
type, then thevalue
must be of a type that is assignment compatible with the field descriptor type. - If the field is
final
, it must be declared in the current class, and the instruction must occur in the<clinit>
method of the current class.