小傅哥 | https://bugstack.cn
沉淀、分享、成长,专注于原创专题案例,以最易学习编程的方式分享知识,让自己和他人都能有所收获。目前已完成的专题有;Netty4.x实战专题案例、用Java实现JVM、基于JavaAgent的全链路监控、手写RPC框架、架构设计专题案例、源码分析等。
你用剑 、我用刀 ,好的代码都很烧,望你不吝出招!
一、案例介绍
本章主要介绍用java实现一些本地方法类库,并初始化本地方法,之后通过反射命令来调用本地方法。
Java虚拟机和Java类库一起构成了Java运行时环境。Java类库主要用Java语言编写,一些无法用Java语言实现的方法则使用本地语言编写,这额方法叫作本地方法。
OpenJDK类库中的本地方法是用JNI(Java Native Interface)编写的,但是要让虚拟机支持JNI规范还需要大量工作。
二、环境准备
- jdk 1.8.0
- IntelliJ IDEA Community Edition 2018.3.1 x64
三、配置信息
- 调试配置
11. 配置位置:Run/Debug Configurations -> program arguments
12. 配置内容:-Xjre "C:Program FilesJavajdk1.8.0_161jre" E:itstackgitistack-demoitstack-demo-jvmitstack-demo-jvm-09targettest-classesorgitstackdemotestHelloWorld
四、代码示例
1itstack-demo-jvm-09
2
3├── pom.xml
4
5└── src
6
7 └── main
8
9 │ └── java
10
11 │ └── org.itstack.demo.jvm
12
13 │ ├── _native
14
15 │ │ ├── java
16
17 │ │ │ ├── _Class.java
18
19 │ │ │ ├── _Double.java
20
21 │ │ │ ├── _Float.java
22
23 │ │ │ ├── _Object.java
24
25 │ │ │ ├── _String.java
26
27 │ │ │ └── _System.java
28
29 │ │ └── sun
30
31 │ ├── NativeMethod.java
32
33 │ └── Registry.java
34
35 │ ├── classfile
36
37 │ │ ├── attributes
38
39 │ │ ├── constantpool
40
41 │ │ ├── ClassFile.java
42
43 │ │ ├── ClassReader.java
44
45 │ │ └── MemberInfo.java
46
47 │ ├── classpath
48
49 │ │ ├── impl
50
51 │ │ │ ├── CompositeEntry.java
52
53 │ │ │ ├── DirEntry.java
54
55 │ │ │ ├── WildcardEntry.java
56
57 │ │ │ └── ZipEntry.java
58
59 │ │ ├── Classpath.java
60
61 │ │ └── Entry.java
62
63 │ ├── classpath
64
65 │ │ ├── base
66
67 │ │ │ ├── BytecodeReader.java
68
69 │ │ │ ├── ClassInitLogic.java
70
71 │ │ │ ├── Instruction.java
72
73 │ │ │ ├── InstructionBranch.java
74
75 │ │ │ ├── InstructionIndex8.java
76
77 │ │ │ ├── InstructionIndex16.java
78
79 │ │ │ ├── InstructionNoOperands.java
80
81 │ │ │ └── MethodInvokeLogic.java
82
83 │ │ ├── comparisons
84
85 │ │ ├── constants
86
87 │ │ ├── control
88
89 │ │ ├── conversions
90
91 │ │ ├── extended
92
93 │ │ ├── loads
94
95 │ │ ├── math
96
97 │ │ ├── references
98
99 │ │ │ ├── ANEW_ARRAY.java
100
101 │ │ │ ├── ARRAY_LENGTH.java
102
103 │ │ │ ├── CHECK_CAST.java
104
105 │ │ │ ├── GET_FIELD.java
106
107 │ │ │ ├── GET_STATIC.java
108
109 │ │ │ ├── INSTANCE_OF.java
110
111 │ │ │ ├── INVOKE_INTERFACE.java
112
113 │ │ │ ├── INVOKE_SPECIAL.java
114
115 │ │ │ ├── INVOKE_STATIC.java
116
117 │ │ │ ├── INVOKE_VIRTUAL.java
118
119 │ │ │ ├── MULTI_ANEW_ARRAY.java
120
121 │ │ │ ├── NEW.java
122
123 │ │ │ ├── NEW_ARRAY.java
124
125 │ │ │ ├── PUT_FIELD.java
126
127 │ │ │ └── PUT_STATIC.java
128
129 │ │ ├── reserved
130
131 │ │ │ └── INVOKE_NATIVE.java
132
133 │ │ ├── stack
134
135 │ │ ├── store
136
137 │ │ │ └── xastore
138
139 │ │ │ ├── AASTORE.java
140
141 │ │ │ ├── BASTORE.java
142
143 │ │ │ ├── CASTORE.java
144
145 │ │ │ ├── DASTORE.java
146
147 │ │ │ ├── FASTORE.java
148
149 │ │ │ ├── IASTORE.java
150
151 │ │ │ ├── LASTORE.java
152
153 │ │ │ └── SASTORE.java
154
155 │ │ └── Factory
156
157 │ ├── rtda
158
159 │ │ ├── heap
160
161 │ │ │ ├── constantpool
162
163 │ │ │ ├── methodarea
164
165 │ │ │ │ ├── Class.java
166
167 │ │ │ │ ├── ClassMember.java
168
169 │ │ │ │ ├── Field.java
170
171 │ │ │ │ ├── Method.java
172
173 │ │ │ │ ├── MethodDescriptor.java
174
175 │ │ │ │ ├── MethodDescriptorParser.java
176
177 │ │ │ │ ├── MethodLookup.java
178
179 │ │ │ │ ├── Object.java
180
181 │ │ │ │ ├── Slots.java
182
183 │ │ │ │ └── StringPool.java
184
185 │ │ │ └── ClassLoader.java
186
187 │ │ ├── Frame.java
188
189 │ │ ├── JvmStack.java
190
191 │ │ ├── LocalVars.java
192
193 │ │ ├── OperandStack.java
194
195 │ │ ├── Slot.java
196
197 │ │ └── Thread.java
198
199 │ ├── Cmd.java
200
201 │ ├── Interpret.java
202
203 │ └── Main.java
204
205 └── test
206
207 └── java
208
209 └── org.itstack.demo.test
210
211 └── HelloWorld.java
代码片段
_Class.java
1package org.itstack.demo.jvm._native.java;
2
3
4
5import org.itstack.demo.jvm._native.NativeMethod;
6
7import org.itstack.demo.jvm._native.Registry;
8
9import org.itstack.demo.jvm.rtda.Frame;
10
11import org.itstack.demo.jvm.rtda.LocalVars;
12
13import org.itstack.demo.jvm.rtda.OperandStack;
14
15import org.itstack.demo.jvm.rtda.heap.ClassLoader;
16
17import org.itstack.demo.jvm.rtda.heap.methodarea.Class;
18
19import org.itstack.demo.jvm.rtda.heap.methodarea.Object;
20
21import org.itstack.demo.jvm.rtda.heap.methodarea.StringPool;
22
23
24
25/**
26
27 * https://bugstack.cn/
28
29 * create by fuzhengwei on 2019/4/30
30
31 */
32
33public class _Class {
34
35
36
37 private final String jlClass = "java/lang/Class";
38
39
40
41 public _Class() {
42
43 Registry.register(jlClass, "getPrimitiveClass", "(Ljava/lang/String;)Ljava/lang/Class;", new NativeMethod(this, "getPrimitiveClass"));
44
45 Registry.register(jlClass, "getName0", "()Ljava/lang/String;", new NativeMethod(this, "getName0"));
46
47 Registry.register(jlClass, "desiredAssertionStatus0", "(Ljava/lang/Class;)Z", new NativeMethod(this, "desiredAssertionStatus0"));
48
49 Registry.register(jlClass, "registerNatives", "()V", new NativeMethod(this, "registerNatives"));
50
51 }
52
53
54
55 public void registerNatives(Frame frame) {
56
57 // do nothing
58
59 }
60
61
62
63 public void getPrimitiveClass(Frame frame) {
64
65 Object nameObj = frame.localVars().getRef(0);
66
67 String name = StringPool.goString(nameObj);
68
69
70
71 ClassLoader loader = frame.method().clazz().loader();
72
73 Object jClass = loader.loadClass(name).jClass();
74
75
76
77 frame.operandStack().pushRef(jClass);
78
79 }
80
81
82
83 public void getName0(Frame frame) {
84
85 Object thiz = frame.localVars().getThis();
86
87 Class clazz = (Class) thiz.extra();
88
89
90
91 String name = "虚拟机本地方法getName0获取类名:" + clazz.javaName();
92
93 Object nameObj = StringPool.jString(clazz.loader(), name);
94
95
96
97 frame.operandStack().pushRef(nameObj);
98
99 }
100
101
102
103 public void desiredAssertionStatus0(Frame frame) {
104
105 frame.operandStack().pushBoolean(false);
106
107 }
108
109
110
111 public void isInterface(Frame frame) {
112
113 LocalVars vars = frame.localVars();
114
115 Object thiz = vars.getThis();
116
117 Class clazz = (Class) thiz.extra();
118
119
120
121 OperandStack stack = frame.operandStack();
122
123 stack.pushBoolean(clazz.isInterface());
124
125 }
126
127
128
129 public void isPrimitive(Frame frame) {
130
131 LocalVars vars = frame.localVars();
132
133 Object thiz = vars.getThis();
134
135 Class clazz = (Class) thiz.extra();
136
137
138
139 OperandStack stack = frame.operandStack();
140
141 stack.pushBoolean(clazz.IsPrimitive());
142
143 }
144
145
146
147}
_System.java
1package org.itstack.demo.jvm._native.java;
2
3
4
5import org.itstack.demo.jvm._native.NativeMethod;
6
7import org.itstack.demo.jvm._native.Registry;
8
9import org.itstack.demo.jvm.rtda.Frame;
10
11import org.itstack.demo.jvm.rtda.LocalVars;
12
13import org.itstack.demo.jvm.rtda.heap.methodarea.Class;
14
15import org.itstack.demo.jvm.rtda.heap.methodarea.Object;
16
17
18
19/**
20
21 * https://bugstack.cn/
22
23 * create by fuzhengwei on 2019/4/30
24
25 */
26
27public class _System {
28
29
30
31 private final String jlSystem = "java/lang/System";
32
33
34
35 public _System() {
36
37 Registry.register(jlSystem, "arraycopy", "()Ljava/lang/String;", new NativeMethod(this, "arraycopy"));
38
39 Registry.register(jlSystem,"registerNatives", "()V",new NativeMethod(this,"registerNatives"));
40
41 }
42
43
44
45 public void registerNatives(Frame frame) {
46
47 // do nothing
48
49 }
50
51
52
53 public void arraycopy(Frame frame) {
54
55 LocalVars vars = frame.localVars();
56
57 Object src = vars.getRef(0);
58
59 int srcPos = vars.getInt(1);
60
61 Object dest = vars.getRef(2);
62
63 int destPos = vars.getInt(4);
64
65 int length = vars.getInt(4);
66
67
68
69 if (null == src || dest == null) {
70
71 throw new NullPointerException();
72
73 }
74
75
76
77 if (!checkArrayCopy(src, dest)) {
78
79 throw new ArrayStoreException();
80
81 }
82
83
84
85 if (srcPos < 0 || destPos < 0 || length < 0 ||
86
87 srcPos + length > src.arrayLength() ||
88
89 destPos + length > dest.arrayLength()) {
90
91 throw new IndexOutOfBoundsException();
92
93 }
94
95
96
97 System.arraycopy(src, srcPos, dest, destPos, length);
98
99
100
101 //todo 待完善
102
103
104
105 }
106
107
108
109 public boolean checkArrayCopy(Object src, Object dest) {
110
111 Class srcClass = src.clazz();
112
113 Class destClass = dest.clazz();
114
115
116
117 if (!srcClass.isArray() || !destClass.isArray()) {
118
119 return false;
120
121 }
122
123
124
125 if (srcClass.componentClass().IsPrimitive() || destClass.componentClass().IsPrimitive()) {
126
127 return srcClass == destClass;
128
129 }
130
131
132
133 return true;
134
135
136
137 }
138
139
140
141}
NativeMethod.java
1package org.itstack.demo.jvm._native;
2
3
4
5import org.itstack.demo.jvm.rtda.Frame;
6
7
8
9import java.lang.reflect.Method;
10
11
12
13/**
14
15 * https://bugstack.cn/
16
17 * create by fuzhengwei on 2019/4/30
18
19 */
20
21public class NativeMethod {
22
23
24
25 private String methodName;
26
27 private Object obj;
28
29
30
31 public NativeMethod(Object obj, String methodName) {
32
33 this.methodName = methodName;
34
35 this.obj = obj;
36
37 }
38
39
40
41 public void invoke(Frame frame) {
42
43 try {
44
45 Method method = obj.getClass().getMethod(methodName, frame.getClass());
46
47 method.invoke(obj, frame);
48
49 } catch (Exception e) {
50
51 e.printStackTrace();
52
53 }
54
55 }
56
57
58
59}
Registry.java
1package org.itstack.demo.jvm._native;
2
3
4
5import org.itstack.demo.jvm._native.java.*;
6
7
8
9import java.util.HashMap;
10
11import java.util.Map;
12
13
14
15/**
16
17 * https://bugstack.cn/
18
19 * create by fuzhengwei on 2019/4/30
20
21 */
22
23public class Registry {
24
25
26
27 private static Map<String, NativeMethod> registry = new HashMap<>();
28
29
30
31 //初始化本地方法
32
33 public static void initNative() {
34
35 new _Class();
36
37 new _Double();
38
39 new _Float();
40
41 new _Object();
42
43 new _String();
44
45 new _System();
46
47 }
48
49
50
51 public static void register(String className, String methodName, String methodDescriptor, NativeMethod method) {
52
53 String key = className + "~" + methodName + "~" + methodDescriptor;
54
55 registry.put(key, method);
56
57 }
58
59
60
61 public static NativeMethod findNativeMethod(String className, String methodName, String methodDescriptor) {
62
63 String key = className + "~" + methodName + "~" + methodDescriptor;
64
65 return registry.get(key);
66
67 }
68
69
70
71}
INVOKE_NATIVE.java
1package org.itstack.demo.jvm.instructions.reserved;
2
3
4
5import org.itstack.demo.jvm._native.NativeMethod;
6
7import org.itstack.demo.jvm._native.Registry;
8
9import org.itstack.demo.jvm.instructions.base.InstructionNoOperands;
10
11import org.itstack.demo.jvm.rtda.Frame;
12
13import org.itstack.demo.jvm.rtda.heap.methodarea.Method;
14
15
16
17/**
18
19 * https://bugstack.cn/
20
21 * create by fuzhengwei on 2019/5/2
22
23 */
24
25public class INVOKE_NATIVE extends InstructionNoOperands {
26
27
28
29 @Override
30
31 public void execute(Frame frame) {
32
33 Method method = frame.method();
34
35 String className = method.clazz().name();
36
37 String methodName = method.name();
38
39 String methodDescriptor = method.descriptor();
40
41
42
43 NativeMethod nativeMethod = Registry.findNativeMethod(className, methodName, methodDescriptor);
44
45 if (null == nativeMethod) {
46
47 String methodInfo = className + "." + methodName + methodDescriptor;
48
49 throw new UnsatisfiedLinkError(methodInfo);
50
51 }
52
53
54
55 nativeMethod.invoke(frame);
56
57
58
59 }
60
61
62
63}
ClassLoader.java
1package org.itstack.demo.jvm.rtda.heap;
2
3
4
5import org.itstack.demo.jvm.classfile.ClassFile;
6
7import org.itstack.demo.jvm.classpath.Classpath;
8
9import org.itstack.demo.jvm.rtda.heap.constantpool.AccessFlags;
10
11import org.itstack.demo.jvm.rtda.heap.methodarea.*;
12
13import org.itstack.demo.jvm.rtda.heap.constantpool.RunTimeConstantPool;
14
15import org.itstack.demo.jvm.rtda.heap.methodarea.Class;
16
17import org.itstack.demo.jvm.rtda.heap.methodarea.Object;
18
19
20
21import java.util.HashMap;
22
23import java.util.Map;
24
25
26
27/*
28
29class names:
30
31 - primitive types: boolean, byte, int ...
32
33 - primitive arrays: [Z, [B, [I ...
34
35 - non-array classes: java/lang/Object ...
36
37 - array classes: [Ljava/lang/Object; ...
38
39*/
40
41public class ClassLoader {
42
43
44
45 private Classpath classpath;
46
47 private Map<String, Class> classMap;
48
49
50
51 public ClassLoader(Classpath classpath) {
52
53 this.classpath = classpath;
54
55 this.classMap = new HashMap<>();
56
57
58
59 this.loadBasicClasses();
60
61 this.loadPrimitiveClasses();
62
63 }
64
65
66
67 private void loadBasicClasses() {
68
69 Class jlClassClass = this.loadClass("java/lang/Class");
70
71 for (Map.Entry<String, Class> entry : this.classMap.entrySet()) {
72
73 Class clazz = entry.getValue();
74
75 if (clazz.jClass == null) {
76
77 clazz.jClass = jlClassClass.newObject();
78
79 clazz.jClass.extra = clazz;
80
81 }
82
83 }
84
85 }
86
87
88
89 private void loadPrimitiveClasses() {
90
91 for (Map.Entry<String, String> entry : ClassNameHelper.primitiveTypes.entrySet()) {
92
93 loadPrimitiveClass(entry.getKey());
94
95 }
96
97 }
98
99
100
101 private void loadPrimitiveClass(String className) {
102
103 Class clazz = new Class(AccessFlags.ACC_PUBLIC,
104
105 className,
106
107 this,
108
109 true);
110
111 clazz.jClass = this.classMap.get("java/lang/Class").newObject();
112
113 clazz.jClass.extra = clazz;
114
115 this.classMap.put(className, clazz);
116
117 }
118
119
120
121 public Class loadClass(String className) {
122
123 Class clazz = classMap.get(className);
124
125 if (null != clazz) return clazz;
126
127
128
129 //'['数组标识
130
131 if (className.getBytes()[0] == '[') {
132
133 clazz = loadArrayClass(className);
134
135 } else {
136
137 clazz = loadNonArrayClass(className);
138
139 }
140
141
142
143 Class jlClazz = this.classMap.get("java/lang/Class");
144
145 if (null != jlClazz && null != clazz) {
146
147 clazz.jClass = jlClazz.newObject();
148
149 clazz.jClass.extra = clazz;
150
151 }
152
153
154
155 return clazz;
156
157 }
158
159
160
161 private Class loadArrayClass(String className) {
162
163 Class clazz = new Class(AccessFlags.ACC_PUBLIC,
164
165 className,
166
167 this,
168
169 true,
170
171 this.loadClass("java/lang/Object"),
172
173 new Class[]{
174
175 this.loadClass("java/lang/Cloneable"),
176
177 this.loadClass("java/io/Serializable")});
178
179 this.classMap.put(className, clazz);
180
181 return clazz;
182
183 }
184
185
186
187 private Class loadNonArrayClass(String className) {
188
189 try {
190
191 byte[] data = this.classpath.readClass(className);
192
193 if (null == data) {
194
195 throw new ClassNotFoundException(className);
196
197 }
198
199 Class clazz = defineClass(data);
200
201 link(clazz);
202
203 return clazz;
204
205 } catch (Exception e) {
206
207 e.printStackTrace();
208
209 return null;
210
211 }
212
213 }
214
215
216
217 private void link(Class clazz) {
218
219 verify(clazz);
220
221 prepare(clazz);
222
223 }
224
225
226
227 private void prepare(Class clazz) {
228
229 calcInstanceFieldSlotIds(clazz);
230
231 calcStaticFieldSlotIds(clazz);
232
233 allocAndInitStaticVars(clazz);
234
235 }
236
237
238
239 private void allocAndInitStaticVars(Class clazz) {
240
241 clazz.staticVars = new Slots(clazz.staticSlotCount);
242
243 for (Field field : clazz.fields) {
244
245 if (field.isStatic() && field.isFinal()) {
246
247 initStaticFinalVar(clazz, field);
248
249 }
250
251 }
252
253 }
254
255
256
257 private void initStaticFinalVar(Class clazz, Field field) {
258
259 Slots staticVars = clazz.staticVars;
260
261 RunTimeConstantPool constantPool = clazz.runTimeConstantPool;
262
263 int cpIdx = field.constValueIndex();
264
265 int slotId = field.slotId();
266
267
268
269 if (cpIdx > 0) {
270
271 switch (field.descriptor()) {
272
273 case "Z":
274
275 case "B":
276
277 case "C":
278
279 case "S":
280
281 case "I":
282
283 java.lang.Object val = constantPool.getConstants(cpIdx);
284
285 staticVars.setInt(slotId, (Integer) val);
286
287 break;
288
289 case "J":
290
291 staticVars.setLong(slotId, (Long) constantPool.getConstants(cpIdx));
292
293 break;
294
295 case "F":
296
297 staticVars.setFloat(slotId, (Float) constantPool.getConstants(cpIdx));
298
299 break;
300
301 case "D":
302
303 staticVars.setDouble(slotId, (Double) constantPool.getConstants(cpIdx));
304
305 break;
306
307 case "Ljava/lang/String;":
308
309 String goStr = (String) constantPool.getConstants(cpIdx);
310
311 Object jStr = StringPool.jString(clazz.loader(), goStr);
312
313 staticVars.setRef(slotId, jStr);
314
315 break;
316
317 }
318
319 }
320
321
322
323 }
324
325
326
327 private void calcStaticFieldSlotIds(Class clazz) {
328
329 int slotId = 0;
330
331 for (Field field : clazz.fields) {
332
333 if (field.isStatic()) {
334
335 field.slotId = slotId;
336
337 slotId++;
338
339 if (field.isLongOrDouble()) {
340
341 slotId++;
342
343 }
344
345 }
346
347 }
348
349 clazz.staticSlotCount = slotId;
350
351 }
352
353
354
355 private void calcInstanceFieldSlotIds(Class clazz) {
356
357 int slotId = 0;
358
359 if (clazz.superClass != null) {
360
361 slotId = clazz.superClass.instanceSlotCount;
362
363 }
364
365 for (Field field : clazz.fields) {
366
367 if (!field.isStatic()) {
368
369 field.slotId = slotId;
370
371 slotId++;
372
373 if (field.isLongOrDouble()) {
374
375 slotId++;
376
377 }
378
379 }
380
381 }
382
383 clazz.instanceSlotCount = slotId;
384
385 }
386
387
388
389 private void verify(Class clazz) {
390
391 // 校验字节码,尚未实现
392
393 }
394
395
396
397 private Class defineClass(byte[] data) throws Exception {
398
399 Class clazz = parseClass(data);
400
401 clazz.loader = this;
402
403 resolveSuperClass(clazz);
404
405 resolveInterfaces(clazz);
406
407 this.classMap.put(clazz.name, clazz);
408
409 return clazz;
410
411 }
412
413
414
415 private void resolveInterfaces(Class clazz) throws Exception {
416
417 int interfaceCount = clazz.interfaceNames.length;
418
419 if (interfaceCount > 0) {
420
421 clazz.interfaces = new Class[interfaceCount];
422
423 for (int i = 0; i < interfaceCount; i++) {
424
425 clazz.interfaces[i] = clazz.loader.loadClass(clazz.interfaceNames[i]);
426
427 }
428
429 }
430
431 }
432
433
434
435 private void resolveSuperClass(Class clazz) throws Exception {
436
437 if (!clazz.name.equals("java/lang/Object")) {
438
439 clazz.superClass = clazz.loader.loadClass(clazz.superClassName);
440
441 }
442
443 }
444
445
446
447 private Class parseClass(byte[] data) {
448
449 ClassFile classFile = new ClassFile(data);
450
451 return new Class(classFile);
452
453 }
454
455
456
457
458
459}
HelloWorld.java
1package org.itstack.demo.test;
2
3
4
5/**
6
7 * -Xjre "C:Program FilesJavajdk1.8.0_161jre" E:itstackgitistack-demoitstack-demo-jvmitstack-demo-jvm-09targettest-classesorgitstackdemotestHelloWorld -verbose true -args 你好,java版虚拟机v1.0,欢迎你的到来。
8
9 */
10
11public class HelloWorld {
12
13
14
15 public static void main(String[] args) {
16
17 System.out.println(byte.class.getName()); // byte
18
19 System.out.println(void.class.getName()); // void
20
21 System.out.println(boolean.class.getName()); // boolean
22
23 System.out.println(char.class.getName()); // cha
24
25 System.out.println(short.class.getName()); // short
26
27 System.out.println(int.class.getName()); // int
28
29 System.out.println(long.class.getName()); // long
30
31 System.out.println(float.class.getName()); // float
32
33 System.out.println(double.class.getName()); // double
34
35 System.out.println(Object.class.getName()); // java.lang.Object
36
37 System.out.println(int[].class.getName()); // [I
38
39 System.out.println(int[][].class.getName()); // [[I
40
41 System.out.println(Object[].class.getName()); // [Ljava.lang.Object;
42
43 System.out.println(Object[][].class.getName()); // [[Ljava.lang.Object;
44
45 }
46
47
48
49}
五、测试结果
1虚拟机本地方法getName0获取类名:byte
2
3虚拟机本地方法getName0获取类名:void
4
5虚拟机本地方法getName0获取类名:boolean
6
7虚拟机本地方法getName0获取类名:cha
8
9虚拟机本地方法getName0获取类名:short
10
11虚拟机本地方法getName0获取类名:int
12
13虚拟机本地方法getName0获取类名:long
14
15虚拟机本地方法getName0获取类名:float
16
17虚拟机本地方法getName0获取类名:double
18
19虚拟机本地方法getName0获取类名:java.lang.Object
20
21虚拟机本地方法getName0获取类名:[I
22
23虚拟机本地方法getName0获取类名:[[I
24
25虚拟机本地方法getName0获取类名:[Ljava.lang.Object;
26
27虚拟机本地方法getName0获取类名:[[Ljava.lang.Object;