简介
本篇文章主要是以“认识”为主,所谓的认识就是,你不需要关注里边的细节,只需要大概了解,”认识一下“就好
klass是什么
没有拼错
首先要声明的是,就是klass不是class没有拼错
先建立一个概念
我们的java代码要想运行起来,首先要被编译成class字节码,再把class字节码加载到jvm虚拟机中,由jvm进一步处理。jvm又是什么呢?, 大家现在只需要两点
- 它是由c++编写的
- c++是面向对象的语言
设身处地想一个问题
如果此时让你用java,创造一门编程语言,姑且叫它,“haha”(放心,我们只是假设,并不是真的去设计,大可不必担心自己没学过编译原理),
实现一个超简单的功能
haha语言的语法如下
我们设想一下该如何实现:
- 首先一定是读取haha文件,
- 其次是解析出 hlass类名,及function(方法)
- 解析好之后我们肯定还要吧类的信息记录下来,比如类名(因为记录下来才能再调用whoAmI的时候把类名打印出来)
划重点: 把类的信息记录下来
如何记录类的信息呢 ?
很简单如果在java中,我们一定是这样做
public class HaHaHlassInfo {
/**
* 记录haha类的类名
*/
private String hlassName;
/**
* 记录haha类中所有的方法
*/
private List HahaFunctions;
}
没错,java是面向对象的语言,在面向对象语言的世界中一切皆对象,所以我们用一个对象(类)来保存haha的类信息
回到jvm
还记得我们刚刚讲的吗?,c++也是面向对象的语言,正如你所想的klass就是c++中用来描述java类信息的类。准确的说是基类(父类)
一探究竟
我们口说无凭,看不见摸不着的东西总是抽象的,下面我们就来看一看具体的东西
非数组类
我们先看一看java中的非数组类,在c++中对应的klass是什么样子的?
如何看
这就要介绍一款,jdk自带的工具hsdb了,它能看到我们的java对象在JVM里是什么样子
下面开始演示
第一步
运行我们的java程序
程序很简单,写一个read()方法让方法不要结束
第二步
查看进程号
(3345)
第三步
启动hsdb
- 进入jdk的lib目录
- 执行
java -cp sa-jdi.jar sun.jvm.hotspot.HSDB
- attach到进程
- 输入进程号
- 选择类浏览
- 然后就能看到我们的java类的内存地址了
记下这个内存地址(也就是0x00000000100061dd0)
- 选择inspector
- 输入内存地址
第四步
到这我们就可以看到有个叫instanceKlass的“东西”
instanceKlass与klass是什么关系?
我们在前面说了,klass相当于基类,那么instanceKlass就是子类喽
我们看一眼代码
通过代码也清楚的看到InstanceKlass继承了Klass
非数组类看得差不多了,再来看看数组类
基本类型数组
看看它在内存里什么样子
比如 int bool
- 准备好java代码
在代码中我们创建一个integer类型的数组
- 同样的方法attach到java进程
- 观察main方法的栈内存
因为数组是运行时生成的类型(你想想java中数组是不是没有对应的类,而是用 “类型[]” 表示),所以我们不能通过类浏览来找到它,而是通过查看main的栈内存
- 找到在内存中的地址
可以看到这个地有一个符号 “[I” 这个就是int数组的标识,我们记下它的内存地址
- 到inspector中检索
可以看到与之对应的是TypeArrayKlass
看看代码
TypeArrayKlass继承了ArrayKlass
ArrayKlass继承了Klass
完善一下类图
非基本类型数组
看完了基本类型数组再来看看非基本类型数组
看看它在内存中是什么样子
方法与基本类型数组一样,我们直接看结果
可以看到它的类型是ObjArrayKlass
ObjArrayKlass同样继承了ArrayKlass类
完善一下类图
最后看一眼InstanceMirrorKlass
保证知识的完整性我们搂一眼InstanceMirrorKlass
顾名思义“镜像类”,它是什么呢?
它对应的就是我们java中的Class类
最后来一张完整的类图,和他们在内存的位置
到这java中所有类型在c++中对应的类我们就介绍完了