Java中如何模拟指针操作,以迁移C++代码

[color=blue][size=large]1.前言[/size][/color]
前段时间做了一项重要的工作,就是将原来开源的ICTCLAS的C++代码,全部迁移到了Java语言重新实现,在迁移完成以后,初步测试没有啥大问题,在此过程中得到了一点小小的经验,特记录下来,以供大家参考。

[color=blue][size=large]2.问题的分析[/size][/color]
虽然说Java语言是从C++演化过来,语法关键词基本类似,但C++语言和Java语言相比,有一个最为关键的不同,就是Java不支持指针,无法直接进行地址的计算,这样的话,就给代码迁移带来了很大的困难。
例如下面这段代码,是C++的原始代码。

bool CContextStat::GetItem(int nKey,PMYCONTEXT *pItemRet)
{//Get the item according the nKey
PMYCONTEXT pCur=m_pContext,pPrev=NULL;
if(nKey==0&&m_pContext)
{
*pItemRet=m_pContext;
return true;
}
while(pCur!=NULL&&pCur->nKey<nKey)
{//delete the context array
pPrev=pCur;
pCur=pCur->next;
}
if(pCur!=NULL&&pCur->nKey==nKey)
{//find it and return the current item
*pItemRet=pCur;
return true;
}
*pItemRet=pPrev;
return false;
}


在这段代码中,要将这段代码使用Java来实现,最为头疼的地方就是*这个操作符号了,因为Java里面不能直接操作内存地址,因此必须采用转换的方式来进行模拟实现。

[color=blue][size=large]3.解决思路[/size][/color]
在C语言里面,*操作符号和&操作符号是相对的,一个用来将指针所在地址赋值,一个用来获取一个内存地址。而在Java里面,内存地址是无法直接访问,也无法直接获取的。
因此在上面的例子中,我们首先定义一个PMYCONTEXT类。这个类代表一个一级指针。

/**
* PMYCONTEXT的定义是一个指向结构体MYCONTEXT的指针, 是一个一级指针
* @author liujunsong
*
*/
public class PMYCONTEXT {
public MYCONTEXT p=null;// The chain pointer to next Context
/**
* 带参数的构造函数
* @param tag
*/
public PMYCONTEXT(MYCONTEXT tag){
p=tag;
}

/**
* 得到下一个节点,通过封装p来实现。
* @return
*/
public PMYCONTEXT next(){
if(p!=null){
return p.next;
}else{
return null;
}
}

/**
* 从当前节点开始,递归到各个下级节点,然后释放所有链表的内存
* 这个方法用来释放内存。
*/
public void DestroyAll(){
PMYCONTEXT pCur=next(),pTemp;
//递归清理所有下级的节点
while(pCur!=null){
pTemp=pCur.next(); //得到下一节点
pCur.p.Destroy(); //当前节点内存释放
pCur=pTemp; //指向下一节点
}
//清理本级指针对应节点
if(p!=null){
p.Destroy();
p=null;
}
}

}

但在原来的C语言代码中,输入参数采用PMYCONTEXT *pItemRet的方式,实际上定义了一个二级指针出来,而Java不支持这样的直接定义,所以我们需要另外一个专门的二级指针对象,来模拟这个C语言里面的二级指针对象。

/**
* 一个指向MYCONTEXT的二级指针
* @author liujunsong
*
*/
public class PPMYCONTEXT {
public PMYCONTEXT p=null;

/**
* 唯一可用的构造函数,可以传入一个null
* @param point
*/
public PPMYCONTEXT(PMYCONTEXT point){
p=point;
}

/**
* 重新设置指针的值,这一方法不会生成新的PPMYCONTEXT对象
* 也不会重新分配内存。
* @param point
*/
public void setValue(PMYCONTEXT point){
p=point;
}
}

有了这样一个对应的二级指针定义以后,就可以直接上面提到的C++语言代码,直接迁移改造成同等算法的Java代码,结果如下:

/**
* 利用给定的key值,来检索一个MYCONTEXT对象,返回一个ppItemRet,二级指针
* <P>
* 在二级指针中设置指针的数据,不新增加内存。
*
* @param nKey
* @param pItemRet
* @return
*/
private boolean GetItem(int nKey, PPMYCONTEXT pItemRet) {
// Get the item according the nKey

PMYCONTEXT pCur = _copy(m_pContext), pPrev = null;

if (nKey == 0 && !_isNullPoint(m_pContext)) {
pItemRet.setValue(m_pContext); // 如果nkey==0,返回头元素
return true;
}

// pCur有效的情况下,循环查找,来按照nKey来查找
// 此处代码有一个bug,假设是按照nkey来排序的
// 但在Add的时候并没有进行排序处理
// 所以要修改一个判断条件为不相等
while (_isNotNullPoint(pCur) && pCur.p.nKey != nKey) {
pPrev = _copy(pCur);
pCur = _copy(pCur.next());
}

// 循环结束,判断循环结束点
if (_isNotNullPoint(pCur) && pCur.p.nKey == nKey) {
// find it and return the current item
pItemRet.setValue(pCur);
return true;
}

pItemRet.setValue(pPrev); // 设置最后一个有效节点
return false;
}

修改完成以后经过测试,程序运行正常。

[color=blue][size=large]4.小结[/size][/color]
ictclas本身代码量有将近1M,原来的数据结构设计的非常严格,算法设计的也很巧妙,对于指针的使用非常频繁,几乎没有一段代码不涉及到指针的使用,采用上面这种方式进行数据结构的模拟,指针的模拟以后,在很短的时间内就将全部代码迁移到了Java语言重新实现。经过初步测试,系统功能完全正常。
同时由于存在一个作为样板目标的C++代码存在,当系统发生异常的时候,可以很方便的进行代码比较跟踪,查看那里修改算法出现了错误,这样就提高了程序开发的效率和质量。
欢迎大家下载本blog发布的ictclas,Java改写版本,其中附带有C++源代码,可以对比查看,确定效果如何。
如果大家还有其他C++代码迁移的案例,欢迎一起来讨论学习。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java,虽然没有指针的概念,但可以通过引用来实现类似指针操作。在C++指针可以进行四种基本操作:取地址、解引用、指针加法和指针减法。下面分别介绍如何在Java模拟这四种操作: 1. 取地址 在C++,通过&符号可以获取一个变量的地址。在Java,可以使用Object类的hashCode()方法获取对象的地址值。例如: ```java Object obj = new Object(); int address = obj.hashCode(); ``` 2. 解引用 在C++,通过*符号可以解引用一个指针,获取指针指向的变量的值。在Java,可以使用对象的成员变量来实现类似的操作。例如: ```java class Node { int value; Node next; } Node node = new Node(); node.value = 10; // 解引用 int value = node.value; ``` 3. 指针加法 在C++,可以对指针进行加法操作,使其指向指定的位置。在Java,可以使用数组来实现类似的操作。例如: ```java int[] arr = new int[10]; int address = arr.hashCode(); // 指针加法 int index = 2; int elementAddress = address + index * 4; ``` 4. 指针减法 在C++,可以对指针进行减法操作,计算出两个指针之间的距离。在Java,可以使用数组的下标来计算两个元素之间的距离。例如: ```java int[] arr = new int[10]; int address = arr.hashCode(); // 指针减法 int index1 = 2; int index2 = 5; int distance = (index2 - index1) * 4; // 4是int类型的字节数 ``` 需要注意的是,在Java,引用类型变量存储的是对象的地址,而不是对象本身。因此,对引用类型变量进行赋值时,实际上是将一个地址赋给了另一个变量,而不是复制对象本身。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值