java.lang.Class&ClassObject

在java语言里的特殊的类java.lang.Class,它保存了类的信息。我们可以用它得到类的名字、成员、方法包括构造方法等等。举个例子,我们写java.lang.String stringClass=Class.forName(“java.lang.String”);于是我们得到了java.lang.Class的一个实例,它存储的信息是关于java.lang.String这个类型的信息。注意不要和newInstance()搞起来,它是创建一个对象,而且forName的静态方法,newInstance是实例方法。

而在java虚拟机中,java.lang.Class的一个实例就对应ClassObject这个类的一个对象。一般同一个类型在虚拟机中只存在一个ClassObject,因为当程序需要某个类型的ClassObject的时候会到存放ClassObject的已加载的类型的哈希表中查找,有的话会直接返回,没有的话则创建一个ClassObject加入这个哈希表中。

同时,ClassObject还可以表示原始类型。boolean,char,float,double,byte,short,int,long,引用。这些类型都是虚拟机初始化的时候创建的。

先看一个结构:Object。

typedef struct Object {

ClassObject*    clazz;      //类型对象

Lock           lock;        /*锁对象,只要是实例对象都有对应的锁,某个线程获得对它的锁以后,如果其它线程要获得它的锁,只有等这个线程释放了它的锁,才能真正获得锁。*/

} Object;

/*类的状态,随着进展而改变*/

typedef enum ClassStatus {

CLASS_ERROR             = -1,       /*出错了*/

CLASS_NOTREADY      = 0,        /*刚开始,什么也没做*/

CLASS_LOADED            = 1,        /*已加载*/

CLASS_PREPARED          = 2,        /*已准备,连接的一部分*/

CLASS_RESOLVED          = 3,        /*已解析,连接的一部分*/

CLASS_VERIFYING         = 4,        /*正在验证,逻辑上属于连接的一部分*/

CLASS_VERIFIED          = 5,        /*验证完毕,逻辑上属于连接的一部分,准备初始化*/

CLASS_INITIALIZING      = 6,        /*初始化中*/

CLASS_INITIALIZED       = 7,        /*初始化好了,全好了,可以用了*/

} ClassStatus;

这是Dalvik虚拟机类型生命周期开始的图解。

typedef enum PrimitiveType {

PRIM_NOT            = -1,

PRIM_BOOLEAN        = 0,

PRIM_CHAR           = 1,

PRIM_FLOAT          = 2,

PRIM_DOUBLE         = 3,

PRIM_BYTE           = 4,

PRIM_SHORT          = 5,

PRIM_INT            = 6,

PRIM_LONG           = 7,

PRIM_VOID           = 8,

PRIM_MAX

} PrimitiveType;

关于类的方法的调用:

1.     如果是一个接口的引用调用方法就一定是invokeinterface。否则2

2.     如果是调用静态方法就一定是invokestatic。否则3

3.     如果是super关键字调用方法,不管是super(…)还是super….(…)就一定是调用invokespecial。否则4

4.     如果是调用<init>方法就一定是invokespecial。否则5

5.     如果是调用私有方法就一定是调用invokespecial。否则6

6.     余下的都是调用invokervirtual。

/*用于ClassObject的iftable列表中*/

typedef struct InterfaceEntry {

ClassObject*        clazz;  /*表示接口的ClassObject对象*/

/*指向在vtable中对应方法的位置偏移的索引数组ifviPool中的位置偏移的索引数组(详见图)*/

int*                methodIndexArray;

} InterfaceEntry;

struct Method {

/*方法所属的类型*/

ClassObject*        clazz;

/*方法的访问标志,可以为ACC_PUBLIC、ACC_PRIVATE、ACC_PROTECTED、ACC_STATIC、ACC_FINAL、ACC_SYNCHRONIZED、ACC_BRIDGE、ACC_VARARGS、ACC_NATIVE、ACC_ABSTRACT、ACC_STRICT、ACC_SYNTHETIC、ACC_CONSTRUCTOR和ACC_DECLARED_SYNCHRONIZED及其组合 */

u4              accessFlags;

/*对于虚方法,这个是方法在虚方法表中的偏移;对于接口表的入口这是方法的偏移即iftable[n]->methodIndexArray*/

u2             methodIndex;

/*对于本地方法,我们通过参数列表来计算大小,最初始的时候令insSize和registerSize都等于这个结果*/

u2              registersSize;  /* ins + locals */

u2              outsSize;

u2              insSize;

/*方法名,比如"<init>" 或 "eatLunch" */

const char*         name;

/*方法原型描述字符串*/

DexProto        prototype;

/*方法描述字符串的缩短形式*/

const char*         shorty;

/*剩下的变量不被用于抽象和本地方法中(JNI认为”insns”是一个函数指针,在第一次被调用之后设置。对于内部的本地方法,这是NULL。) */

/*实际代码所在的首地址*/

const u2*           insns;          /*指令,通过内存映像的.dex文件*/

/*缓冲的JNI参数和返回类型提示*/

int                 jniArgInfo;

/*本地方法指针。可以是真正的函数也可以是JNI桥。当前我们并不区分DalvikBridgeFunc和DalvikNativeFunc,前者的参数是个超集(有额外的两个参数,它们会被忽略)。必要的话我们可以使用insns==NULL来判断是JNI桥还是内部本地函数*/

DalvikBridgeFunc nativeFunc;

};

struct Field {

ClassObject*        clazz;         /*所属的类型*/

const char*         name;         /*变量的名称*/

const char*         signature;      /*变量的签名比如"I", "[C", "Landroid/os/Debug;"等等*/

u4              accessFlags;      /*访问标志,可以是ACC_PUBLIC、ACC_PRIVATE、ACC_PROTECTED、ACC_STATIC、ACC_FINAL、ACC_VOLATILE、ACC_TRANSIENT、ACC_SYNTHETIC和ACC_ENUM及其组合*/

};

struct StaticField {

Field               field;           /*必须是第一项*/

JValue              value;          /*对于原始类型直接由DEX设置*/

};

struct InstField {

Field               field;           /*必须是第一项*/

/*从Object*地址处开始的偏移位置*/

int                 byteOffset;

};

struct DataObject {

Object          obj;                /*必须是第一项*/

/* u4类型项的变量数;u8使用两项*/

u4              instanceData[1];

};

struct StringObject {

Object          obj;                /*必须是第一项*/

/* u4类型项的变量数;u8使用两项*/

u4              instanceData[1];

};

struct ArrayObject {

Object          obj;                /*必须是第一项*/

/*元素个数,初始化后不会改变*/

u4              length;

/*数组的内容,大小为length * sizeof(type)。总长度必须是8字节对齐的,实际分配的大小可能小于8字节*/

u8              contents[1];

};

下面让我们看看ClassObject是怎样的。

struct ClassObject {

/*必须放在第一个,你可以看到后面的几个结构,如DataObject、StringObject和ArrayObject都是这样安排为的是获得实例数据时有统一的偏移便于实例数据的获取*/

Object          obj;

/*为实例数据流出4字节的空间*/

u4              instanceData[CLASS_FIELD_SLOTS];

/*UTF-8的描述字符串*/

const char*         descriptor;

/*另一个描述字符串,现在发现好像在反射机制的代理类用到*/

char*          descriptorAlloc;

/*访问标志,对于外部类而言,可以是ACC_PUBLIC、ACC_FINAL、ACC_INTERFACE、ACC_ABSTRACT、ACC_SYNTHETIC、ACC_ANNOTATION和ACC_ENUM的组合;对于内部类而言,可以是ACC_CLASS_MASK、ACC_PRIVATE、ACC_PROTECTED和ACC_STATIC的组合*/

u4              accessFlags;

/* 指向对应的DexFile当从常量池中查询信息时要用到,如果是虚拟机自己生成的类,比如数组和原始类等等则为空*/

DvmDex*        pDvmDex;

/*类的状态,按顺序可以是CLASS_NOTREADY、CLASS_LOADED 、CLASS_PREPARED、CLASS_RESOLVED、CLASS_VERIFYING、CLASS_VERIFIED      、CLASS_INITIALIZING、CLASS_INITIALIZED以及CLASS_ERROR*/

ClassStatus         status;

/*类验证失败时抛出的异常的类型,如果以后又访问这个类则可以直接获得这个类型*/

ClassObject*        verifyErrorClass;

/*初始化时的线程id,用于在<clinit>发生嵌套调用时作检查*/

u4              initThreadId;

/*这个类型所对应的对象的大小,用于在堆上分配内存时使用。如果是接口或抽象类,这个值就是0*/

size_t         objectSize;

/*数组元素的类型,仅当这个类型为数组类型时有效。用于instanceof操作符或强制类型转换时使用,比如String[][][]类型的这个值就是String类型*/

ClassObject*        elementClass;

/*这个类型对应的数组类型,当这个类型的数组类型被首次用到时才被创建和赋值*/

ClassObject*        arrayClass;

/*数组的维数,仅当这个类型为数组时才有效,比如int[][]的值为2 */

int                 arrayDim;

/*原始类型的下标,用于虚拟机生成的原始类型,非原始类型时为PRIM_NOT (-1) */

PrimitiveType       primitiveType;

/*超类的类型,如果是java.lang.Object的话这个值为NULL */

ClassObject*        super;

/*这个类的定义加载器,如果类型为“bootstrap”的系统类加载器则为NULL[微软用户1] */

Object*             classLoader;

/*需要初始化这个类的加载器的列表,即这个类的初始化加载器的列表*/

Object**            initiatingLoaders;

/*这个类的初始化加载器数*/

int                 initiatingLoaderCount;

/*本类直接实现的接口数*/

int                 interfaceCount;

/*本类直接实现的接口列表*/

ClassObject**       interfaces;

/*所谓的direct方法即static,private和<init>方法数*/

int                 directMethodCount;

/*directr方法列表*/

Method*        directMethods;

/*本类定义的虚方法数*/

int                 virtualMethodCount;

/*本类定义的虚方法,所谓虚方法就是通过虚方法表vtable来调用的方法*/

Method*        virtualMethods;

/*虚方法表中的方法数*/

int                 vtableCount;

/*虚方法表,通过invokevirtual来调用。首先从超类完全复制过来虚表,然后我们再部分得替换它或者扩展它*/

Method**       vtable;

/*类实现的接口数*/

int                 iftableCount;

/*类的接口表,每个接口一个表项。不管是由类直接实现的接口,还是由超类间接实现的接口。如果一个接口都未实现那么这个表就为NULL*/

InterfaceEntry*     iftable;

/*在vtable中对应方法的位置偏移的索引数组中的元素个数*/

int                 ifviPoolCount;

/*指向在vtable中对应方法的位置偏移的索引数组*/

int*                ifviPool;

/*静态变量个数*/

int                 sfieldCount;

/*静态变量的数组*/

StaticField*        sfields;

/*实例变量的个数*/

int                 ifieldCount;

/*实例变量中引用的个数*/

int                 ifieldRefCount;

/*实例变量数组*/

InstField*          ifields;

/*源文件的文件名*/

const char*         sourceFile;

};

bool dvmClassStartup(void)

{

ClassObject* unlinkedClass; //供加载和连接时假的引用类对象

……

gDvm.loadedClasses =

dvmHashTableCreate(256, (HashFreeFunc) dvmFreeClassInnards);    //供加载类的哈希表

……

unlinkedClass = &gDvm.unlinkedJavaLangClassObject;

memset(unlinkedClass, 0, sizeof(*unlinkedClass));

DVM_OBJECT_INIT(&unlinkedClass->obj, NULL);

unlinkedClass->descriptor = "!unlinkedClass";

gDvm.unlinkedJavaLangClass = unlinkedClass;

assert(gDvm.bootClassPath == NULL);

processClassPath(gDvm.bootClassPathStr, true);

……

return true;

}

void dvmClassShutdown(void)

{

int i;

dvmHashTableFree(gDvm.loadedClasses);

gDvm.loadedClasses = NULL;

for (i = 0; i < PRIM_MAX; i++)

dvmFreeClassInnards(gDvm.primitiveClass[i]);

freeCpeArray(gDvm.bootClassPath);

gDvm.bootClassPath = NULL;

dvmLinearAllocDestroy(NULL);

}

findClassNoInit:

dvmLinkClass:

解析超类à解析每个接口àcreateVtableàcreateIftable

访问控制:

关于成员变量和成员方法的访问控制。

android dalvik vm oo相关推荐

  1. Modify Android dalvik vm heapsize

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 要修改系 ...

  2. Android虚拟机-Dalvik VM架构

    Dalvik, VM会监视所有的程序APK,并且创建依赖关系熟,为每个程序优化代码并存储在Dalvik缓存中.Dalvik VM第一次加载后会生成Cache文件,加速加载,Dalvik Vm的第一次加 ...

  3. Dalvik VM的主要特征

    在Dalvik VM中,一个应用中会定义很多类,编译完成后有很多相应的.class文件,.dex文件吧所有的.class文件内容整合到一个文件中.除了减少整体文件尺寸,I/0操作,也提高了类的查找速度 ...

  4. 替换Android中VM 加载动态库方式

    Android 加载动态库的代码在 dalvik/vm/Native.cpp ( froyo 中是 Native.c),加载的方式就是调用 libdl 中 dlopen, dlsym 这些函数 应该可 ...

  5. Android dalvik GC相关的属性详解

    在dalvik中,GC的类型有三种: 1.GC_EXPLICIT: 应用主动调用System.gc()产生的GC事件. 2.GC_FOR_ALLOC: 内存分配时,发现可用内存不够时触发的GC事件. ...

  6. JVM、DVM(Dalvik VM)和ART虚拟机的区别

    JVM.DVM(Dalvik VM)和ART虚拟机的区别 DVM vs JVM 1.共同点: 都是解释执行 都是每个 OS 进程运行一个 VM,并运行一个单独的程序 在较新版本中(Froyo / Su ...

  7. Android Dalvik、ART及APK编译过程

    强烈建议看罗升阳大神的文章,五年过去,回头看,真的还是经典啊,不要认为几年前的文章没有价值,看一看就知道 妙啊: https://blog.csdn.net/Luoshengyang/article/ ...

  8. Android Dalvik虚拟机

    首先,让我们来思考下面几个问题: 什么是Dalvik虚拟机? Dalvik VM与JVM有什么区别? Dalvik VM有什么新的特点? Dalvik VM的架构是怎么样的? 首先,我得承认第一个问题 ...

  9. Android Dalvik虚拟机内存分配问题

    之前遇到一个android上图片加载不出来的问题,在三星的note3上极容易出现,而在nexus 4上则很难出现.后来通过DDMS观察发现,是某一个模块一直内存泄漏使得内存接近上限,导致一些大图(需要 ...

最新文章

  1. 无标定物体环境下,高分辨率雷达与相机的像素级外参标定
  2. 在线作图丨数据降维方法⑥——消除趋势对应分析(Detrended correspondence analysis, DCA)
  3. kali linux源大全
  4. oracle 增长型分区,oracle 11g 分区表创建(自动按年分区)
  5. XP或Win7系统下grub4dos安装双系统ubuntu(32或64)
  6. 【pyinstaller打包pyqt5编写的项目为exe(脱离环境可运行)】
  7. map平均准确率_第五篇 目标检测评价标准—MAP
  8. 查询所有_学会DSUM函数,轻松搞定所有的数据查询与数据求和
  9. antd picker 使用 如何_如何基于jsoneditor二次封装一个可实时预览的json编辑器组件?(react版)...
  10. 【英语】舞动奇迹--荡漾我心
  11. 从SQL Server中导入/导出 Excel 的基本方法
  12. Linux中用st_mode判断文件类型
  13. 使用R包qpdf用一行代码将多个pdf合并为一个pdf
  14. 【modelarts】华为人工智能平台_modelarts平台系列教程1
  15. dimm和udimm_RDIMM和UDIMM内存的区别
  16. 计算机无法删除tf卡的内容,内存卡的文件删不掉怎么办?
  17. 论文阅读:FVQA: Fact-based Visual Question Answering
  18. 论文代码复现|并行无人机的调度优化问题PDSTSP
  19. 网站优化基本技巧(网站优化的主要工作是什么)
  20. 再议易语言静态编译重定位数目过多

热门文章

  1. 使用Golang语言的分金币作业 你有50枚金币,需要分配给以下几个人:Matthew,Sarah,Augustus,Heidi,Emilie,Peter,Giana,Adriano,Aaro
  2. (翻译)Few-Shot Object Detection with Attention-RPN and Multi-Relation Detector具有注意力RPN和多关系检测器的小样本目标检测
  3. 03基础自绘-05魔法老鼠-magicmouse
  4. IOS APP安全评估工具 Snoop-it
  5. 背景建模技术(四):视频分析(VideoAnalysis)模块
  6. zerossl通配符证书申请教程
  7. 多边形游戏-动态规划(Java)
  8. 局域网计算机统一桌面背景,Windows 2008 R2 AD组策略-统一域用户桌面背景详细图文教程...
  9. 来,带你看看京东“硬核”科技!
  10. Fireeye Mandiant 2014 安全报告 Part1