使用JNI和Reflect实现Object向void*的自动转换之三:学习 [原]
来源:互联网 发布:两院院士 知乎 编辑:程序博客网 时间:2024/05/29 07:58
三、准备:认识它,学习它,理解它,然后改造它
好,我们开始着手做,先起个工程名称,叫做Project JPointer吧。我们应该明确,所要做的是使用C++将java的Object类型转换成void*的一块内存区。
问题很快就来了。
问题一,转换哪些数据,Object的所有成员还是只有public域?或者其他的选择。
问题二,java的数据成员如何对应到c语言中去。结合例子来说,Rect的bottom要对应RECT的bottom,这个如何保证?
问题三,java的数据类型如何对应到C中去。比如Java的int是32位的,是否直接对应到C语言的int? java的基本数据类型的平台无关性如何保证?数据成员是个Object又如何对应?如果是数组哪?
隐隐约约的感到,还有一些C语言的基本问题,比如说结构体对齐等。
这些问题中,一些是要做抉择的,一些则是要研究的。比如说第一个问题,就是个策略选择问题。这里,我们选择了包装Object中的非静态数据成员。这样选择,是为了通常的需要。因为这和C++的内存安排比较接近。C++的静态数据成员是和非静态数据成员分开的。所以,我们的第一反应就是这种包装。尽管你反驳说包装private是不符合面向对象的,但是我们是为了做实际有用的软件设备,如果用户使用我们的设备,就应该明白这种策略。当然,成功的开发了这种策略的设备后,我们当然也可以仿照着做不同策略的设备。
第二个问题,java的数据成员以何种顺序映射到C的结构体中。我们的第一反应是名称对应策略。比如说那个Java的Rect到C的结构体RECT的对应,让Rect的bottom对应了RECT的bottom,而不管两者的声明和定义顺序如何。然而,这种方法是不可行的,因为C程序被编译后不会保存变量的名称,名称对照也就无从谈起。退而求其次,我们可否使用顺序映射策略哪?这就要研究了,C语言没问题,结构体内存的安排是按照声明的先后来做的,java的Object中数据成员有没有什么顺序哪?声明的顺序是否可由固定的算法保证的哪?这句话的意思反映到Rect上是说,由于left声明了在前,right在后,通过反射机制得到的域数组(Field[])是否也是这个顺序,如果是这个顺序,就可以采用这种顺序映射策略了。
首先查文档,看看java.lang.Class怎么说的。对于域的操作,一个比较有用的是
public Field[] getDeclaredFields() throws SecurityException
而文档中明确说明:The elements in the array returned are not sorted and are not in any particular order.这句话很打击人,让我们的顺序映射策略几乎破产。我们应该就此放弃这个方法吗?不见得,应该动手做做试试,看看顺序如何。
这个实验很简单,就是自己构造一些类,使用这个函数打印出来域的名称。很好,不管我怎么构造,总是按照声明的顺序依次打印出来。比如下面的:
public void testFieldsSequence(){
Object obj = new Object(){
public int first;
private Object second;
protected double third;
};
Class clz = obj.getClass();
Field[] fs = clz.getDeclaredFields();
for(int i = 0; i < fs.length; i++){
System.out.println(fs[i].getName());
}
}
输出结果是:
first
second
third
this$0
这个结果还是比较理想的,表明文档中说的不一定可信。我想写文档的人是为了保证以后留余地的原因吧,也可能不同的虚拟机有不同的机制。这个没有深入研究。但是,做得很多试验,发现Field[]的顺序总是和声明的顺序一致,即使是static数据成员也是如此。
这里,我们应该注意到this$0这个尾巴,由于是局部匿名类,才产生了这个数据成员,不过考虑到这个数据成员是追加到最后的,只是扩充对象的大小,反映到C的结构体中,使得C的结构体变大,不会影响以前的数据,所以,只要不改变这个值,就不用太在意。
好的,第二个问题基本有了答案,我们就采用顺序映射策略。
第三个问题,是关于基本数据类型的映射大小问题。在java平台下,基本数据类型的长度是固定的,比如说int是32位的,double是64位的,这些类型要忠实的表达到依赖于机器的c语言环境中,我们就要考虑数据长度问题了。Java的int类型,在JNI中定义为jint,而jint被定义为c语言的long,就反映了这个问题。所以,基本类型我们可以有如下安排表格:
Java类型
对应的C类型
字长(单位Byte)
boolean
unsigned char
1
byte
signed char
1
short
short
1
char
unsigned short
2
int
long/__int32
4
long
__int64
8
float
float
4
double
double
8
好,这些基本类型的字长都有了规定,我们就要考虑如果出现Object数据成员,如何安排到C的结构体中去,映射成什么类型?应该让一个类去寄存和解释Object去,所以,应该安排一个类的指针给他,比如说上面的second对象,就应该对应一个JObjectPtr*指针。这个JObjectPtr是包装了Object的对象。不过,应该清楚,指针终究是指针,不管是void*还是JObjectPtr*,只要是在Win32的环境下,大小都是32位的。所以,对于C结构体来说,成员变量为Object对应的类型,我们分配空间的时候,仍然只是四个字节,只不过解释它为JObjectPtr*而已。
好,还有数组没有打算好。应该认识到,java的数组和C的数组不同,倒是和C的指针很相似。考虑到实际用途中,我们可以把数组当成一个成员数据类型相同的结构体,比如说如下的int rcArray[4],和RECT结构体是一样的,反映到内存中都是4个整型数依次排列。出于实际的需要,我们考虑这样包装数组。
剩余的问题,比如说C的结构体对齐问题,我们可以在开发过程中解决,因为我们还不太明白这些细节是利是弊。
- 使用JNI和Reflect实现Object向void*的自动转换之三:学习 [原]
- 使用JNI和Reflect实现Object向void*的自动转换之四:实现 [原]
- 使用JNI和Reflect实现Object向void*的自动转换之二:构想 [原]
- 使用JNI和Reflect实现Object向void*的自动转换之五:测试 [原]
- 使用JNI和Reflect实现Object向void*的自动转换之一:问题 [原]
- 【Java学习之三】用JNI实现Java和C语言的数据传递
- jni object的使用
- JAVA学习之反射(1):Class类和java.lang.reflect包的使用
- syslog和getopt_long_only的使用和void *指针强制转换
- Object - C运行时应用(三)——实现NSCoding的自动归档和自动解档
- 学习笔记:ES6之Proxy和Reflect
- OpenCV向JNI层的参数转换
- void和void指针解析(原)
- 在reflect基础上的map和object转化
- C++中任意类型向void的强制转换
- Android Studio JNI学习之(3)-使用SWIG自动生成Jni代码
- reflect的一个使用的例子---------------自动赋值
- 一步步学习java并发编程模式之Active Object模式(三)java实现active object
- 懷念父親12/3
- 如何在VB6中导出EXCEL、FOXPRO格式的表
- 使用JNI和Reflect实现Object向void*的自动转换之一:问题 [原]
- 使用JNI和Reflect实现Object向void*的自动转换之二:构想 [原]
- 使用Perl查找VC工程依赖关系
- 使用JNI和Reflect实现Object向void*的自动转换之三:学习 [原]
- 用java实现简单的多线程下载
- 我的Visual C++入门之路(转载)
- java面试题目
- 使用JNI和Reflect实现Object向void*的自动转换之四:实现 [原]
- 第一次用我的新机子上网
- 应用可扩展性实践之路(一) --纵向拦截和横行拦截
- 使用JNI和Reflect实现Object向void*的自动转换之五:测试 [原]
- 详细解说 STL 排序(Sort)