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的填充。