我目前正在开发一个用Java编写的项目.我们有一堆用C/C++编写的算法(至少几百个)需要合并到我们的项目中.我们的两个选择是使用JNI来调用此代码,或者用Java重写所有算法.
我知道使用JNI的后果,它可以打开一组全新的问题,这就是为什么用Java重写所有代码甚至被考虑的原因.但重写它的想法似乎......错了.据我所知,算法已经过测试和工作,它们只是用错了语言.
在这种情况下,JNI能否轻松完成这项任务?或者它会比重写Java中的代码更令人头痛吗?
编辑#1: 相关问题 - JNI的用处
编辑#2: 仅供参考 - 我们的Java项目无意以任何方式移植.这可能会消除JNI的一个缺点,因为它可能会降低可移植性.
简单的答案是,如果代码将被调用很多并且性能很重要,那么将其转换为Java.
更复杂的答案是:
如果库容易包装在JNI中,那么请使用JNI
如果您对C/C++代码的测试很容易转换为Java,那么请转到端口
我会做以下事情:
采用其中一种算法并将其包装在JNI中
采用相同的算法并将其转换为Java
看看哪个更痛苦
如果速度很重要,那么对两个版本进行分析,看看哪些版本是可以接
我认为答案在于调用java代码和调用的C/C++代码之间的耦合量以及重写所需的工作量.如果你的C代码需要几个整数,那么就做一些毛茸茸的计算,并返回另一个int.使用JNI.如果有很多复杂的来回,但算法相当简单,重写'em.故障线是JNI连接.如果这将变得复杂,您最终可能会编写更多的JNI接口代码而不是算法代码进行重写.
如果"算法"包装得很好,也许可以通过JNI创建一些自动胶水代码?这样可以减少错误的风险(手动创建数百个单独的组件听起来很冒险),并且使成本与要添加的算法数量无关,或多或少.
重写数百个组件听起来非常危险,我肯定会建议至少首先更密切地调查JNI.
算法对项目的其余部分有哪些I/O要求?如果它们相当松散耦合,也许可以将它们作为独立的独立程序运行,从Java调用子流程并使用例如stdio来共享数据?
我认为你会发现使用JNI并不像潜水之前那样令人生畏.有一些重要的权衡和限制,但总的来说JNI效果很好,并且很容易按照你的意愿来利用.
正如其他人所说,JNI的最佳案例是:
复杂的原生代码(如果该代码已被证明非常可靠,则可获得奖励积分
Java和本机代码之间的最小来回(您希望最小化跨JNI层的行程)
对本机代码的调用接口相当简单(如果本机代码需要利用Java对象/方法,也可以返回Java)
绝对有可能为一组合理结构的本机组件自动化或伪自动化创建JNI层.如果要换行的组件数量很大,那将是非常值得的.
JNI的好消息是,您应该直接构建和测试此接口,例如,您应该能够从Java编写利用现有算法行为的测试用例,如果有问题,他们很可能会在JNI中图层本身而不是算法(鉴于您对本机实现的信心).
用Java重写大量的C/C++算法似乎比使用JNI风险更大.当然,在不了解细节的情况下很难衡量,但我认为影响算法实际实现的技术之间存在细微差别,更不用说纯粹的工程工作和错误风险.
最后的考虑因素是这些算法或相关组件的未来生命.算法集是或多或少完整,或者您是否继续添加?无论哪种方式,是否有强大的维护和/或未来的发展理由支持一种技术而不是另一种?例如,如果其他所有内容都使用Java,并且所有新算法都使用Java,并且团队中的每个人几乎总是使用Java进行编码,那么Java中的重新实现开始看起来更具吸引力.
然而即便如此,工作胜过一致.对于大量运行良好的本机组件,即使您要长期过渡到Java,我仍然倾向于从JNI开始.
我仍然认真考虑选择JNI,特别是如果你能够最小化跨语言接口的数量.
例如,如果有一堆C函数都具有相同的输入和输出,但只是对输入做了不同的工作,请将其包含在一个带有附加参数的JNI包装器中,以指定要使用的特定算法.
如果您打算用Java编写未来的项目,而不是C/C++.我现在会咬紧牙关,将代码移植到java.你等待的时间越长,它就越糟糕.在这种情况下,JNI听起来很有吸引力,但是当其他人都参与有趣的新Java项目时,你会遇到有人必须维护C++代码的问题.
如果这是一次性Java项目,那么为什么要用Java编写它?