Interview questions:
How many objects will the following code create? [Do not consider constant pool]
class Main{
public static void main(String[] args){
String a = "Hello ";
String b = "World";
String c = a + b ;
System.out.println(c);
}
}
String overview
The java.lang.String class represents a string. The variables defined by the String class can be used to point to a string object and then operate on the string.
All string literals in Java programs (for example: "abc") are objects of this class.
Detailed explanation of the characteristics of String class
String is actually often called an immutable string type, and its objects cannot be changed after they are created.
We use the javac compiler to first compile into a class file, run it through java, and finally analyze it through javap.
Here we can see that there are many words that can be left behind. Let’s take a look at the following standard document explanations one by one. I have extracted them here, let’s take a look at them together.
Main();'s parameterless constructor Code part (any class has a default parameterless constructor).
aload_0: Push the first int type local variable to the top of the stack.
invokespecial: Call parent class methods, instance initialization methods, and private methods.
return: Return void from the current method.
Code part of main function main:
ldc: Push the int, float or String type constant value from the constant pool to the top of the stack.
astore_1: Store the int type value at the top of the stack into the second local variable.
new: Create an object and push its reference value onto the top of the stack.
dup: Copy the value on the top of the stack and push the copied value onto the top of the stack.
getstatic: Get the static field of the specified class and push its value to the top of the stack.
The above is the mnemonic explanation that appears in the interpreter. Based on these explanations, we can almost understand it.
String a = "Hello ";// String Hello creates an object
String b = "World"; // String World creates a second object
String c = a + b ;//First, the c variable obtains a separate address. Because it is [new], there are only three objects. Later, because you can see [// Method java/lang/StringBuilder."<init>" :()V] stands for instantiation, here is another object, now the fourth one. The accumulation of strings uses [Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;]. This append step does not add objects. In step [#7] [// Method java/lang/StringBuilder.toString:()Ljava/lang/String;] no new object is created because the toString source code is as follows:
public String toString() {
return this;
}
So here are 4 objects.
System.out.println(c); // Field java/lang/System.out:Ljava/io/PrintStream; Because PrintStream is used, an object will be created again. [#9] uses the function that comes with PrintStream. Therefore, there is no need to create objects, and [5] objects are finally created.
Mnemonic comparison table
Let's take a look at the standard document explanation. All mnemonics have corresponding links for detailed viewing.
Classification | opcode | help token | Command meaning | |
---|---|---|---|---|
constant |
0 |
|
do nothing |
|
1 |
|
Push null to the top of the stack |
||
2 |
|
Push int type -1 to the top of the stack |
||
3 |
|
Push int type 0 to the top of the stack |
||
4 |
|
Push int type 1 to the top of the stack |
||
5 |
|
Push int type 2 to the top of the stack |
||
6 |
|
Push int type 3 to the top of the stack |
||
7 |
|
Push int type 4 to the top of the stack |
||
8 |
|
Push int type 5 to the top of the stack |
||
9 |
|
Push long type 0 to the top of the stack |
||
10 |
|
Push long type 1 to the top of the stack |
||
11 |
|
Push float type 0 to the top of the stack |
||
12 |
|
Push float type 1 to the top of the stack |
||
13 |
|
Push float type 2 to the top of the stack |
||
14 |
|
Push double type 0 to the top of the stack |
||
15 |
|
Push double type 1 to the top of the stack |
||
16 |
|
Push a single-byte constant value (-128 ~ 127) to the top of the stack |
||
17 |
|
Push a short integer constant value (-32,768 ~ 32,767) to the top of the stack |
||
18 |
|
Push a constant value of type int, float or String from the constant pool to the top of the stack |
||
19 |
|
Push a constant value of type int, float or String from the constant pool to the top of the stack (wide index) |
||
20 |
|
Push a long or double type constant value from the constant pool to the stack (wide index) |
||
load |
21 |
|
Push the specified int type local variable to the top of the stack |
|
22 |
|
Push the specified long type local variable to the top of the stack |
||
23 |
|
Push the specified float type local variable to the top of the stack |
||
24 |
|
Push the specified double type local variable to the top of the stack |
||
25 |
|
Push the local variable of the specified reference type to the top of the stack |
||
26 |
|
Push the first local variable of type int to the top of the stack |
||
27 |
|
Push the second local variable of type int to the top of the stack |
||
28 |
|
Push the third local variable of type int to the top of the stack |
||
29 |
|
Push the fourth int type local variable to the top of the stack |
||
30 |
|
Push the first long type local variable to the top of the stack |
||
31 |
|
Push the second long type local variable to the top of the stack |
||
32 |
|
Push the third long type local variable to the top of the stack |
||
33 |
|
Push the fourth long type local variable to the top of the stack |
||
34 |
|
Push the first local variable of float type to the top of the stack |
||
35 |
|
Push the second float type local variable to the top of the stack |
||
36 |
|
Push the third float type local variable to the top of the stack |
||
37 |
|
将第 4 个 float 类型本地变量推送至栈顶 |
||
38 |
|
将第 1 个 double 类型本地变量推送至栈顶 |
||
39 |
|
将第 2 个 double 类型本地变量推送至栈顶 |
||
40 |
|
将第 3 个 double 类型本地变量推送至栈顶 |
||
41 |
|
将第 4 个 double 类型本地变量推送至栈顶 |
||
42 |
|
将第 1 个引用类型本地变量推送至栈顶 |
||
43 |
|
将第 2 个引用类型本地变量推送至栈顶 |
||
44 |
|
将第 3 个引用类型本地变量推送至栈顶 |
||
45 |
|
将第 4 个引用类型本地变量推送至栈顶 |
||
46 |
|
将 int 类型数组的指定元素推送至栈顶 |
||
47 |
|
将 long 类型数组的指定元素推送至栈顶 |
||
48 |
|
将 float 类型数组的指定元素推送至栈顶 |
||
49 |
|
将 double 类型数组的指定元素推送至栈顶 |
||
50 |
|
将引用类型数组的指定元素推送至栈顶 |
||
51 |
|
将 boolean 或 byte 类型数组的指定元素推送至栈顶 |
||
52 |
|
将 char 类型数组的指定元素推送至栈顶 |
||
53 |
|
将 short 类型数组的指定元素推送至栈顶 |
||
存储 |
54 |
|
将栈顶 int 类型数值存入指定本地变量 |
|
55 |
|
将栈顶 long 类型数值存入指定本地变量 |
||
56 |
|
将栈顶 float 类型数值存入指定本地变量 |
||
57 |
|
将栈顶 double 类型数值存入指定本地变量 |
||
58 |
|
将栈顶引用类型数值存入指定本地变量 |
||
59 |
|
将栈顶 int 类型数值存入第 1 个本地变量 |
||
60 |
|
将栈顶 int 类型数值存入第 2 个本地变量 |
||
61 |
|
将栈顶 int 类型数值存入第 3 个本地变量 |
||
62 |
|
将栈顶 int 类型数值存入第 4 个本地变量 |
||
63 |
|
将栈顶 long 类型数值存入第 1 个本地变量 |
||
64 |
|
将栈顶 long 类型数值存入第 2 个本地变量 |
||
65 |
|
将栈顶 long 类型数值存入第 3 个本地变量 |
||
66 |
|
将栈顶 long 类型数值存入第 4 个本地变量 |
||
67 |
|
将栈顶 float 类型数值存入第 1 个本地变量 |
||
68 |
|
将栈顶 float 类型数值存入第 2 个本地变量 |
||
69 |
|
将栈顶 float 类型数值存入第 3 个本地变量 |
||
70 |
|
将栈顶 float 类型数值存入第 4 个本地变量 |
||
71 |
|
将栈顶 double 类型数值存入第 1 个本地变量 |
||
72 |
|
将栈顶 double 类型数值存入第 2 个本地变量 |
||
73 |
|
将栈顶 double 类型数值存入第 3 个本地变量 |
||
74 |
|
将栈顶 double 类型数值存入第 4 个本地变量 |
||
75 |
|
将栈顶引用类型数值存入第 1 个本地变量 |
||
76 |
|
将栈顶引用类型数值存入第 2 个本地变量 |
||
77 |
|
将栈顶引用类型数值存入第 3 个本地变量 |
||
78 |
|
将栈顶引用类型数值存入第 4 个本地变量 |
||
79 |
|
将栈顶 int 类型数值存入指定数组的指定索引位置 |
||
80 |
|
将栈顶 long 类型数值存入指定数组的指定索引位置 |
||
81 |
|
将栈顶 float 类型数值存入指定数组的指定索引位置 |
||
82 |
|
将栈顶 double 类型数值存入指定数组的指定索引位置 |
||
83 |
|
将栈顶引用类型数值存入指定数组的指定索引位置 |
||
84 |
|
将栈顶 boolean 或 byte 类型数值存入指定数组的指定索引位置 |
||
85 |
|
将栈顶 char 类型数值存入指定数组的指定索引位置 |
||
86 |
|
将栈顶 short 类型数值存入指定数组的指定索引位置 |
||
栈 |
87 |
|
将栈顶数值弹出(数值不能是 long 或 double 类型的) |
|
88 |
|
将栈顶的一个 long 或 double 类型的数值或两个其他类型的数值弹出 |
||
89 |
|
复制栈顶数值并将复制值压入栈顶 |
||
90 |
|
复制栈顶值并将其插入栈顶那两个值的下面 |
||
91 |
|
复制栈顶值并将其插入栈顶那两个或三个值的下面 |
||
92 |
|
复制栈顶的一个 long 或 double 类型的值,或两个其他类型的值,并将其压入栈顶 |
||
93 |
|
复制栈顶的一个或两个值,并将其插入栈顶那两个或三个值的下面 |
||
94 |
|
复制栈顶的一个或两个值,并将其插入栈顶那两个、三个或四个值的下面 |
||
95 |
|
将栈顶的两个数值互换(数值不能是 long 或 double 类型的) |
||
数学 |
96 |
|
将栈顶两 int 类型数值相加并将结果压入栈顶 |
|
97 |
|
将栈顶两 1ong 类型数值相加并将结果压入栈顶 |
||
98 |
|
将栈顶两 float 类型数值相加并将结果压入栈顶 |
||
99 |
|
将栈顶两 double 类型数值相加并将结果压入栈顶 |
||
100 |
|
将栈顶两 int 类型数值相减并将结果压入栈顶 |
||
101 |
|
将栈顶两 long 类型数值相减并将结果压入栈顶 |
||
102 |
|
将栈顶两 float 类型数值相减并将结果压入栈顶 |
||
103 |
|
将栈顶两 double 类型数值相减并将结果压入栈顶 |
||
104 |
|
将栈顶两 int 类型数值相乘并将结果压入栈顶 |
||
105 |
|
将栈顶两 long 类型数值相乘并将结果压入栈顶 |
||
106 |
|
将栈顶两 float 类型数值相乘并将结果压入栈顶 |
||
107 |
|
将栈顶两 double 类型数值相乘并将结果压入栈顶 |
||
108 |
|
将栈顶两 int 类型数值相除并将结果压入栈顶 |
||
109 |
|
将栈顶两 long 类型数值相除并将结果压入栈顶 |
||
110 |
|
将栈顶两 float 类型数值相除并将结果压入栈顶 |
||
111 |
|
将栈顶两 double 类型数值相除并将结果压入栈顶 |
||
112 |
|
将栈顶两 int 类型数值作取模运算并将结果压入栈顶 |
||
113 |
|
将栈顶两 long 类型数值作取模运算并将结果压入栈顶 |
||
114 |
|
将栈顶两 float 类型数值作取模运算并将结果压入栈顶 |
||
115 |
|
将栈顶两 double 类型数值作取模运算并将结果压入栈顶 |
||
116 |
|
将栈顶 int 类型数值取负并将结果压入栈顶 |
||
117 |
|
将栈顶 long 类型数值取负并将结果压入栈顶 |
||
118 |
|
将栈顶 float 类型数值取负并将结果压入栈顶 |
||
119 |
|
将栈顶 double 类型数值取负并将结果压入栈顶 |
||
120 |
|
将 int 类型数值左移位指定位数并将结果压入栈顶 |
||
121 |
|
将 long 类型数值左移位指定位数并将结果压入栈顶 |
||
122 |
|
将 int 类型数值(有符号)右移位指定位数并将结果压入栈顶 |
||
123 |
|
将 long 类型数值(有符号)右移位指定位数并将结果压入栈顶 |
||
124 |
0x7c |
将 int 类型数值(无符号)右移位指定位数并将结果压入栈顶 |
||
125 |
|
将 long 类型数值(无符号)右移位指定位数并将结果压入栈顶 |
||
126 |
|
将栈顶两 int 类型数值作“按位与”并将结果压入栈顶 |
||
127 |
|
将栈顶两 long 类型数值作“按位与”并将结果压入栈顶 |
||
128 |
|
将栈顶两 int 类型数值作“按位或”并将结果压入栈顶 |
||
129 |
0x81 |
将栈顶两 long 类型数值作“按位或”并将结果压入栈顶 |
||
130 |
|
将栈顶两 int 类型数值作“按位异或”并将结果压入栈顶 |
||
131 |
|
将栈顶两 long 类型数值作“按位异或”并将结果压入栈顶 |
||
132 |
|
将指定 int 类型变量增加指定值( |
||
转换 |
133 |
|
将栈顶 int 类型数值强制转换成 long 类型数值并将结果压入栈顶 |
|
134 |
|
将栈顶 int 类型数值强制转换成 float 类型数值并将结果压入栈顶 |
||
135 |
|
将栈顶 int 类型数值强制转换成 double 类型数值并将结果压入栈顶 |
||
136 |
|
将栈顶 long 类型数值强制转换成 int 类型数值并将结果压入栈顶 |
||
137 |
|
将栈顶 long 类型数值强制转换成 float 类型数值并将结果压入栈顶 |
||
138 |
|
将栈顶 long 类型数值强制转换成 double 类型数值并将结果压入栈顶 |
||
139 |
|
将栈顶 float 类型数值强制转换成 int 类型数值并将结果压入栈顶 |
||
140 |
|
将栈顶 float 类型数值强制转换成 long 类型数值并将结果压入栈顶 |
||
141 |
|
将栈顶 float 类型数值强制转换成 double 类型数值并将结果压入栈顶 |
||
142 |
|
将栈顶 double 类型数值强制转换成 int 类型数值并将结果压入栈顶 |
||
143 |
|
将栈顶 double 类型数值强制转换成 long 类型数值并将结果压入栈顶 |
||
144 |
|
将栈顶 double 类型数值强制转换成 float 类型数值并将结果压入栈顶 |
||
145 |
|
将栈顶 int 类型数值强制转换成 byte 类型数值并将结果压入栈顶 |
||
146 |
|
将栈顶 int 类型数值强制转换成 char 类型数值并将结果压入栈顶 |
||
147 |
|
将栈顶 int 类型数值强制转换成 short 类型数值并将结果压入栈顶 |
||
比较 |
148 |
|
比较栈顶两 long 类型数值大小,并将结果(1,0,-1)压入栈顶 |
|
149 |
|
比较栈顶两 float 类型数值大小,并将结果(1,0,-1)压入栈顶;当其中一个数值为“NaN”时,将 -1 压入栈顶 |
||
150 |
|
比较栈顶两 float 类型数值大小,并将结果(1,0,-1)压入栈顶;当其中一个数值为“NaN”时,将1压入栈顶 |
||
151 |
|
比较栈顶两 double 类型数值大小,并将结果(1,0,-1)压入栈顶;当其中一个数值为“NaN”时,将-1压入栈顶 |
||
152 |
|
比较栈顶两 double 类型数值大小,并将结果(1,0,-1)压入栈顶;当其中一个数值为“NaN”时,将1压入栈顶 |
||
153 |
|
当栈顶 int 类型数值等于 0 时跳转 |
||
154 |
|
当栈顶 int 类型数值不等于 0 时跳转 |
||
155 |
|
当栈顶 int 类型数值小于 0 时跳转 |
||
156 |
|
当栈顶 int 类型数值大于等于 0 时跳转 |
||
157 |
|
当栈顶 int 类型数值大于 0 时跳转 |
||
158 |
|
当栈顶 int 类型数值小于等于 0 时跳转 |
||
159 |
|
比较栈顶两 int 类型数值大小,当前者等于后者时跳转 |
||
160 |
|
比较栈顶两 int 类型数值大小,当前者不等于后者时跳转 |
||
161 |
|
比较栈顶两 int 类型数值大小,当前者小于后者时跳转 |
||
162 |
|
比较栈顶两 int 类型数值大小,当前者大于等于后者时跳转 |
||
163 |
|
比较栈顶两 int 类型数值大小,当前者大于后者时跳转 |
||
164 |
|
比较栈顶两 int 类型数值大小,当前者小于等于后者时跳转 |
||
165 |
|
比较栈顶两引用类型数值,当结果相等时跳转 |
||
166 |
|
比较栈顶两引用类型数值,当结果不相等时跳转 |
||
控制 |
167 |
|
无条件跳转 |
|
168 |
|
跳转至指定 16 位 offset 位置,并将 jsr 下一条指令地址压入栈顶 |
||
169 |
|
返回至由指定的局部变量所给出的指令位置(一般与 jsr、jsr_w 联合使用) |
||
170 |
|
用于 switch 条件跳转,case 值连续(变长指令) |
||
171 |
|
用于 switch 条件跳转,case 值不连续(变长指令) |
||
172 |
|
从当前方法返回 int |
||
173 |
|
从当前方法返回 long |
||
174 |
|
从当前方法返回 float |
||
175 |
|
从当前方法返回 double |
||
176 |
|
从当前方法返回对象引用 |
||
177 |
|
从当前方法返回void |
||
引用 |
178 |
|
获取指定类的静态字段,并将其值压入栈顶 |
|
179 |
|
为指定类的静态字段赋值 |
||
180 |
|
获取指定类的实例字段,并将其值压入栈顶 |
||
181 |
|
为指定类的实例字段赋值 |
||
182 |
|
调用实例方法 |
||
183 |
|
Call parent class methods, instance initialization methods, private methods |
||
184 |
|
Call static method |
||
185 |
|
Call interface method |
||
186 |
|
Call dynamic link method |
||
187 |
|
Create an object and push its reference value onto the stack |
||
188 |
|
Create an array of specified primitive type (such as int, float, char, etc.) and push its reference value onto the top of the stack |
||
189 |
|
Create an array of reference types (such as classes, interfaces, arrays) and push its reference value onto the top of the stack |
||
190 |
|
Get the length value of the array and push it to the top of the stack |
||
191 |
|
Throw the exception at the top of the stack |
||
192 |
0xcO |
Check type conversion. If the check fails, ClassCastException will be thrown. |
||
193 |
0xc1 |
Tests whether the object is an instance of the specified class. If so, push 1 to the top of the stack, otherwise push 0 to the top of the stack. |
||
194 |
|
Obtain the object's lock, used to implement synchronized blocks |
||
195 |
|
Releases the object's lock for implementing synchronized blocks |
||
Expand |
196 |
|
Extend the width of local variable index |
|
197 |
|
Create a multi-dimensional array of the specified type and specified dimensions (when executing this instruction, the operation stack must contain the length value of each dimension), and push its reference value onto the top of the stack |
||
198 |
|
Jump when it is nu11 |
||
199 |
|
Jump when it is not nu11 |
||
200 |
|
Unconditional jump (wide index) |
||
201 |
|
Jump to the specified 32-bit offset position and push the address of the next instruction of jsr_w onto the top of the stack |
||
Reserved instructions |
202 |
|
breakpoint |
Breakpoint markers during debugging |
254 |
|
impdep1 |
Language backdoors reserved for specific software aspects |
|
255 |
|
impdep2 |
Language backdoors reserved for specific hardware |
Summarize:
When encountering similar interview questions, don't be anxious, just analyze it slowly. If it is a written test, it is recommended to slowly write out the compilation process. It is nothing more than creating a separate StringBuffer and adding an object when doing the append operation. It will not be very complicated. .
I wish everyone a smooth interview.