使用JNI和Reflect实现Object向void*的自动转换之四:实现 [原]
来源:互联网 发布:两院院士 知乎 编辑:程序博客网 时间:2024/06/15 11:19
四、实现:使用Composite复合设计模式来实现
我们打算使用C++来实现这个设备,这个工程名为JPointer,它的预期使用方式我们前面说过了,需要再明确一下“持有”这个概念。持有,是指C++中持有对Java层的某个实体的引用。在JNI提供的接口中,类型区别十分明显,每种类型都有相应的操作函数,setIntField和setDoubleField这样的区别,虽然保证了类型安全,但是对于我们实现这个不依赖于类型的软件设备来说,却是个麻烦事。如果有setField这样的函数,我们就不用再关心这些类型区别了,当然,让系统提供这样的结构是不可能的。
由于存在着诸多的类型不同,我们的系统需要有一个体系结构。“持有”这个概念,然我们想到了不同类型需要不同的处理策略。但是,不同类型的处理,总是为了管理它所认识的对象,所以,“持有”就是共同点,所不同的就是不同的类型这个具体点。所以,自然而然的,我们想到了C++的虚函数来抽象这个“持有”概念。这个接口可以如下表达:
class JPtr
{
public:
virtual int getSize()const; //得到内存块大小
virtual int getMemberNum() = 0; //得到数据成员的数目
virtual void setBuffer(void* newData) = 0; //设置数据
virtual void* getBuffer()const=0; //得到缓冲区指针
virtual bool isChanged()const = 0; //缓冲区的数据是否改变
virtual void updateObject() = 0; //从缓冲区中回滚一个对象,覆盖原来的对象
virtual jvalue getValue() = 0; //得到实体引用
virtual void setValue(jvalue val) = 0; //设置新值
virtual Type getType() = 0; //得到被包装对象的类型
virtual ~JPtr(){}
}
这个共同的接口,就表达“持有”的概念了。
再接着设计,我们看到,如果存在数据成员是一个Object类型,又需要对其成员进行包装,这就是一个典型的树形结构。而特殊的叶节点是形如int,double之类的Primitive类型。
所以,想到了复合设计模式(Composite Design Pattern)。从而,很快可以画出整个体系结构来。
这个设计模型就这样出炉了,使用了C++的继承机制,我们最终是为了得到JObjectPtr这个软件设备,其他的类都是为了这个类服务的。这样的安排,还是为了隔离类型的差异,使得每一种类型的开发就很方便。
应该明确,基本数据类型对应的指针类,比如IntPtr的意思是持有的一个java的int数据,而他并不是真正的指针,它负责管理一个java中的int的值的更新提取,当然还有内存分配回收策略。
很快,我们就可以实现IntPtr,比如说它的大小是4字节,初始化的时候,给它分配4字节的内存块,然后保存下来缓冲区,然后当需要GetBuffer的时候,返回之。析构函数就是放掉内存,当接收到更新updateObject消息的时候,就是用int的一套JNI操作函数来执行。具体的可见源代码。
同样,我们实现了其他的基本数据类型的包装类。开发时,先实现IntPtr、DoublePtr类型,然后转到JObjectPtr的开发来。
这个JObjectPtr是关键,我们如何来做它哪?首先,它的构造函数中就要生成缓冲区,算是资源初始策略吧。
生成缓冲区的算法如下:
接受一个jobject类型,
根据java的reflect来得到Object的数据成员,从而得到Field[],
/*第一次循环,解析成员数据*/
For each Field
得到域的访问域,
if 是静态类型
continue;
得到域的名称,并转换名称为C字符串
通过这个字符串得到FieldID
/*这样做看起来很迂回,而不能使用reflect来直接get/set数据域,这是因为访问控制的原因,反射机制对于private和protected类型,限制直接访问的能力,但是JNI提供的系列函数get/set***Filed,是不管访问域的,所以,我们钻了这个一个空子,从而实现了私有成员的包装。J*/
根据域id,得到域的类型,根据类型调用指针构造函数,返回JPtr*。
JPtr* 入链
End for
/*第二次循环计算C结构内存块大小*/
int bufferLength = 0;
for each jptr
bufferLength += jptr.getSize()
end for
/*分配内存*/
buffer = new byte[bufferLength]
/*拷贝数据*/
byte* position = buffer;
/*构造缓冲区*/
for each jptr
memcpy(position,jptr->getBuffer(),jptr-> getSize());
position += jptr-> getSize();
end for
这个过程的详细实作,参见源代码。
updateObject的过程中,也有这个类似的过程。
应该指出,对于数组类型,我们应该做特殊的处理,当然过程和上面的算法类似。- 使用JNI和Reflect实现Object向void*的自动转换之四:实现 [原]
- 使用JNI和Reflect实现Object向void*的自动转换之二:构想 [原]
- 使用JNI和Reflect实现Object向void*的自动转换之三:学习 [原]
- 使用JNI和Reflect实现Object向void*的自动转换之五:测试 [原]
- 使用JNI和Reflect实现Object向void*的自动转换之一:问题 [原]
- jni object的使用
- JNI使用的一些实现
- 使用go reflect实现一套简易的rpc框架
- JNI实现的视频数据转换
- ASP.NET下利用HttpModule实现简体中文向繁体中文的自动转换
- Java实现简体字向繁体字的转换
- 简单实现汉字向拼音的转换
- syslog和getopt_long_only的使用和void *指针强制转换
- 原码、反码和补码的实现
- void指针和memset实现
- DBus glib 实现和使用object
- OpenCV向JNI层的参数转换
- Object转换byte[],byte[]转换Object的传统转换以及AMF的实现方式.(1)
- 使用Perl查找VC工程依赖关系
- 使用JNI和Reflect实现Object向void*的自动转换之三:学习 [原]
- 用java实现简单的多线程下载
- 我的Visual C++入门之路(转载)
- java面试题目
- 使用JNI和Reflect实现Object向void*的自动转换之四:实现 [原]
- 第一次用我的新机子上网
- 应用可扩展性实践之路(一) --纵向拦截和横行拦截
- 使用JNI和Reflect实现Object向void*的自动转换之五:测试 [原]
- 详细解说 STL 排序(Sort)
- 如何学习vc++(vc的用处)
- 利用正则表达式替换功能,将C++注释转变成纯C的注释
- [翻译]-Windows CE 程序设计 (3rd 版)--5.1 公共控件编程
- installshield