本节继续实现一些本地方法。
字符串拼接和String.intern()方法
在Java语言中,通过加号来拼接字符串。作为优化,javac编译器会把字符串拼接操作转换成StringBuilder,比如说下面这段代码:
很可能会被javac优化成下面这样:
|
|
为了运行上面的代码,本节将实现以下3个本地方法:
- System.arrayCopy()
- Fload.floatToRawIntBits()
- Double.doubleToRawLongBits()
可以跟踪下StringBuilder的append()、toString()方法,就可以找到上述方法的调用。
System.arrayCopy()方法
在/native/java/lang包下新建System.go文件,在其中注册arrayCopy()方法,实现代码没有什么特别的地方,就不贴出来了,参照项目源码。
Float.floatToRawIntBits()和Double.doubleToRawLongBits()方法
Float.floatToRawIntBits()和Double.doubleToRawLongBits()方法返回浮点数的编码,这两个方法大同小异而且也比较简单,代码在/native/java/lang包下,可自行参照。
String.intern()方法
之前已经实现了字符串池,但它只能在虚拟机内部使用,下面实现String类的intern()方法,让Java类库也可以使用它。实现代码位于/native/java/lang/String.go文件中,代码也比较简单,不贴了。
测试
在java项目中新建StringTest.java:
测试:
Object.hashCode()、equals()和toString()
Object类有3个非常重要的方法:hashCode()返回对象的哈希码;equals()用来比较两个对象是否相同;toString()返回对象的字符串表示。hashCode()是个本地方法,equals()和toString()则是用Java写的。下面实现hashCode方法,修改/native/java/lang/Object.go文件:
在java项目中新建ObjectTest.java用于测试,代码就不贴出来了,查看项目源码。下面时测试结果:
Object.clone()
Object类提供clone()方法,用来支持对象克隆,这也是一个本地方法,修改/native/java/lang/Object.go文件:
真正的Clone()逻辑在/rtdata/heap/object_clone.go文件中,代码比较长,就不贴出来了,自行查看项目源码。
在java项目中新建CloneTest.java用于测试,代码就不贴出来了,查看项目源码。下面时测试结果:
自动拆装箱
为了更好地融入Java的对象系统,每种基本类型都有一个包装类与之对应。从Java5开始,Java语法增加了自动装箱和拆箱能力,可以在必要时把基本类型转换成包装类型或者反之。这个增强完全是由编译器完成的,Java虚拟机没有做任何调整。
以int类型为例,它的包装类是java.lang.Integer。它提供了2个方法类帮助编译器在int变量和Integer对象之间转换:静态方法value()把int变量包装成Integer对象;实例方法intValue()返回被包装的int变量。查看Integer的源码可以看出,valueOf()方法并不是每次都创建Integer()对象,而是维护了一个缓存池IntegerCache。对于比较下(默认是-128 ~ 127)的int变量,在IntegerCache初始化时就预先加载到了池中,需要用时直接从池里取即可。再看IntegerCache类的实现,其中有一段sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
,调用了虚拟机初始化配置。下面我们先简单来实现下,在/native/sun/misc包下创建VM.go文件,注册initialize()方法:
上面只是一段hack代码,就不细看了,翻译成等价的Java代码就一句话:
最后在invokenative.go文件中导入misc包,就可以测试了,在java项目中新建BoxTest.java文件,代码就不贴出来了,下面给出测试结果:
本地方法调用暂且就学到这里了。