DVM,也就是Dalvik,Android4.4之后,还推出了ART,但没有作为默认虚拟机使用,直到5.0才正式作为默认虚拟机使用。可见,一个好的东西是需要经历一些磨难才能出的来的。
我把Java中的类分成两种:Primitive Type和Class Type,其中,Primitive Type,即我们所说的int、double等,而Class Type,即我们所说的class。而不管是何种Type,它们在虚拟机的实现中,都有自己的Class。Class是一个特殊的类,它不能被用来构造一个对象,只在虚拟机初始化的时候,唯一一次被直接加载。
Java中的每一个类都对应着一个C++的ClassObject,包括了我们所用的int等java原始类型。一个Java类的加载,就是填充这个结构体ClassObject。
虚拟机第一个加载的java类就是Class,以下就是虚拟机没有通过findClass去加载一个类,而是通过直接填充一个ClassObject来定义Class这个类
/* * Initialize the class Class. This has to be done specially, particularly * because it is an instance of itself. */ ClassObject* clazz = (ClassObject*) dvmMalloc(classObjectSize(CLASS_SFIELD_SLOTS), ALLOC_NON_MOVING); if (clazz == NULL) { return false; } DVM_OBJECT_INIT(clazz, clazz); SET_CLASS_FLAG(clazz, ACC_PUBLIC | ACC_FINAL | CLASS_ISCLASS); clazz->descriptor = "Ljava/lang/Class;"; gDvm.classJavaLangClass = clazz; LOGVV("Constructed the class Class.");
Primitive Type在虚拟机中是被enum出来的
/* * Enumeration of all the primitive types. */enum PrimitiveType { PRIM_NOT = 0, /* value is a reference type, not a primitive type */ PRIM_VOID = 1, PRIM_BOOLEAN = 2, PRIM_BYTE = 3, PRIM_SHORT = 4, PRIM_CHAR = 5, PRIM_INT = 6, PRIM_LONG = 7, PRIM_FLOAT = 8, PRIM_DOUBLE = 9,};
Primitive Type不像class type,有一个类所在的路径,它是被规定死了一些对应字母,在JNI编程中,人们又叫它“签名”。
/* (documented in header) */const char* dexGetPrimitiveTypeDescriptor(PrimitiveType type) { switch (type) { case PRIM_VOID: return "V"; case PRIM_BOOLEAN: return "Z"; case PRIM_BYTE: return "B"; case PRIM_SHORT: return "S"; case PRIM_CHAR: return "C"; case PRIM_INT: return "I"; case PRIM_LONG: return "J"; case PRIM_FLOAT: return "F"; case PRIM_DOUBLE: return "D"; default: return NULL; } return NULL;}
Class Type都有一个包名+类名的形式,而在被加载时,它们都变成了如"Ljava/lang/Object”;"Ljava/lang/Object;”就是Java类的祖宗Object。以下是虚拟机在初始化时,所加载的一些基础类,它们在Java的Libcore里面定义。
static struct { ClassObject** ref; const char* name; } classes[] = { /* * Note: The class Class gets special treatment during initial * VM startup, so there is no need to list it here. */ /* The corest of the core classes */ { &gDvm.classJavaLangObject, "Ljava/lang/Object;" }, { &gDvm.exThrowable, "Ljava/lang/Throwable;" }, /* Slightly less core, but still down there, classes */ { &gDvm.classJavaLangClassArray, "[Ljava/lang/Class;" }, { &gDvm.classJavaLangClassLoader, "Ljava/lang/ClassLoader;" }, { &gDvm.classJavaLangObjectArray, "[Ljava/lang/Object;"}, { &gDvm.classJavaLangStackTraceElement, "Ljava/lang/StackTraceElement;" }, { &gDvm.classJavaLangStackTraceElementArray, "[Ljava/lang/StackTraceElement;" }, { &gDvm.classJavaLangString, "Ljava/lang/String;" }, { &gDvm.classJavaLangThread, "Ljava/lang/Thread;" }, { &gDvm.classJavaLangThreadGroup, "Ljava/lang/ThreadGroup;" }, { &gDvm.classJavaLangVMThread, "Ljava/lang/VMThread;" }, /* Arrays of primitive types */ { &gDvm.classArrayBoolean, "[Z" }, { &gDvm.classArrayByte, "[B" }, { &gDvm.classArrayShort, "[S" }, { &gDvm.classArrayChar, "[C" }, { &gDvm.classArrayInt, "[I" }, { &gDvm.classArrayLong, "[J" }, { &gDvm.classArrayFloat, "[F" }, { &gDvm.classArrayDouble, "[D" }, /* Exception classes */ { &gDvm.exAbstractMethodError, "Ljava/lang/AbstractMethodError;" }, { &gDvm.exArithmeticException, "Ljava/lang/ArithmeticException;" }, { &gDvm.exArrayIndexOutOfBoundsException, "Ljava/lang/ArrayIndexOutOfBoundsException;" }, { &gDvm.exArrayStoreException, "Ljava/lang/ArrayStoreException;" }, { &gDvm.exClassCastException, "Ljava/lang/ClassCastException;" }, { &gDvm.exClassCircularityError, "Ljava/lang/ClassCircularityError;" }, { &gDvm.exClassNotFoundException, "Ljava/lang/ClassNotFoundException;" }, { &gDvm.exClassFormatError, "Ljava/lang/ClassFormatError;" }, { &gDvm.exError, "Ljava/lang/Error;" }, { &gDvm.exExceptionInInitializerError, "Ljava/lang/ExceptionInInitializerError;" }, { &gDvm.exFileNotFoundException, "Ljava/io/FileNotFoundException;" }, { &gDvm.exIOException, "Ljava/io/IOException;" }, { &gDvm.exIllegalAccessError, "Ljava/lang/IllegalAccessError;" }, { &gDvm.exIllegalAccessException, "Ljava/lang/IllegalAccessException;" }, { &gDvm.exIllegalArgumentException, "Ljava/lang/IllegalArgumentException;" }, { &gDvm.exIllegalMonitorStateException, "Ljava/lang/IllegalMonitorStateException;" }, { &gDvm.exIllegalStateException, "Ljava/lang/IllegalStateException;" }, { &gDvm.exIllegalThreadStateException, "Ljava/lang/IllegalThreadStateException;" }, { &gDvm.exIncompatibleClassChangeError, "Ljava/lang/IncompatibleClassChangeError;" }, { &gDvm.exInstantiationError, "Ljava/lang/InstantiationError;" }, { &gDvm.exInstantiationException, "Ljava/lang/InstantiationException;" }, { &gDvm.exInternalError, "Ljava/lang/InternalError;" }, { &gDvm.exInterruptedException, "Ljava/lang/InterruptedException;" }, { &gDvm.exLinkageError, "Ljava/lang/LinkageError;" }, { &gDvm.exNegativeArraySizeException, "Ljava/lang/NegativeArraySizeException;" }, { &gDvm.exNoClassDefFoundError, "Ljava/lang/NoClassDefFoundError;" }, { &gDvm.exNoSuchFieldError, "Ljava/lang/NoSuchFieldError;" }, { &gDvm.exNoSuchFieldException, "Ljava/lang/NoSuchFieldException;" }, { &gDvm.exNoSuchMethodError, "Ljava/lang/NoSuchMethodError;" }, { &gDvm.exNullPointerException, "Ljava/lang/NullPointerException;" }, { &gDvm.exOutOfMemoryError, "Ljava/lang/OutOfMemoryError;" }, { &gDvm.exRuntimeException, "Ljava/lang/RuntimeException;" }, { &gDvm.exStackOverflowError, "Ljava/lang/StackOverflowError;" }, { &gDvm.exStaleDexCacheError, "Ldalvik/system/StaleDexCacheError;" }, { &gDvm.exStringIndexOutOfBoundsException, "Ljava/lang/StringIndexOutOfBoundsException;" }, { &gDvm.exTypeNotPresentException, "Ljava/lang/TypeNotPresentException;" }, { &gDvm.exUnsatisfiedLinkError, "Ljava/lang/UnsatisfiedLinkError;" }, { &gDvm.exUnsupportedOperationException, "Ljava/lang/UnsupportedOperationException;" }, { &gDvm.exVerifyError, "Ljava/lang/VerifyError;" }, { &gDvm.exVirtualMachineError, "Ljava/lang/VirtualMachineError;" }, /* Other classes */ { &gDvm.classJavaLangAnnotationAnnotationArray, "[Ljava/lang/annotation/Annotation;" }, { &gDvm.classJavaLangAnnotationAnnotationArrayArray, "[[Ljava/lang/annotation/Annotation;" }, { &gDvm.classJavaLangReflectAccessibleObject, "Ljava/lang/reflect/AccessibleObject;" }, { &gDvm.classJavaLangReflectConstructor, "Ljava/lang/reflect/Constructor;" }, { &gDvm.classJavaLangReflectConstructorArray, "[Ljava/lang/reflect/Constructor;" }, { &gDvm.classJavaLangReflectField, "Ljava/lang/reflect/Field;" }, { &gDvm.classJavaLangReflectFieldArray, "[Ljava/lang/reflect/Field;" }, { &gDvm.classJavaLangReflectMethod, "Ljava/lang/reflect/Method;" }, { &gDvm.classJavaLangReflectMethodArray, "[Ljava/lang/reflect/Method;"}, { &gDvm.classJavaLangReflectProxy, "Ljava/lang/reflect/Proxy;" }, { &gDvm.classJavaNioReadWriteDirectByteBuffer, "Ljava/nio/ReadWriteDirectByteBuffer;" }, { &gDvm.classOrgApacheHarmonyDalvikDdmcChunk, "Lorg/apache/harmony/dalvik/ddmc/Chunk;" }, { &gDvm.classOrgApacheHarmonyDalvikDdmcDdmServer, "Lorg/apache/harmony/dalvik/ddmc/DdmServer;" }, { &gDvm.classOrgApacheHarmonyLangAnnotationAnnotationFactory, "Lorg/apache/harmony/lang/annotation/AnnotationFactory;" }, { &gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMember, "Lorg/apache/harmony/lang/annotation/AnnotationMember;" }, { &gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMemberArray, "[Lorg/apache/harmony/lang/annotation/AnnotationMember;" }, { NULL, NULL } };
上面还只是一个部分罗列,不过您也应该能看到很多熟悉又陌生的“类”了吧。DVM在初始化时,就把这些基础类保存下来了,以便于人们可以用来定义其他的类。那么加载呢?真正的加载,是通过initClassReference()方法初始化的。
static bool initClassReference(ClassObject** pClass, const char* name) { ClassObject* result; assert(*pClass == NULL); if (name[0] == '[') { result = dvmFindArrayClass(name, NULL); } else { result = dvmFindSystemClassNoInit(name); } if (result == NULL) { ALOGE("Could not find essential class %s", name); return false; } *pClass = result; return true;}
而initClassReference()方法又是通过dvmFindArrayClass()和dvmFindSystemClassNoInit()来加载的,这里可以简单的把它们都看成findClass()。
findClass(),就是我们所说的一个类的加载,也就是完成结构体ClassObject的填充。