IKVM是Microsoft .NET Framework和Mono平台上的一个Java实现,他包括以下一些部分:
1. 一个用.NET实现的Java虚拟机
2. Java类库的.NET实现
3. 一些用于Java和.NET之间互操作的工具集
IKVM提供2种主要的方式在.NET平台上运用Java项目。一种是动态方式,即通过IKVM .NET实现的JVM直接运行Java项目,这种方式需要动态的将Java的class或者jar等文件编译成.NET的CIL, 所以启动的时候会比较慢。另外一种是静态方式,即使用IKVM的工具先将class、jar文件编译为.NET的CIL程序集,然后在.NET framework上运行这些程序集,这种方式可以在.NET开发 中直接使用Java的类库
项目组件、程序集介绍参考这里:
1. ikvm.exe,基本对应于java.exe的功能,用于动态运行方式
2. ikvmc.exe,基本对应于javac.exe的功能,用于静态方式
3. ikvmstub.exe,为.NET程序集生成Java class的代理文件,以便在Java中使用.NET程序集的功能

这个项目目前仍然非常活跃,从04年开始到现在一直在开发更新中。对于纯粹基于JDK的Java项目,IKVM目前应该能够处理的比较完善了, 对于使用了Swing和JNI的Java项目,IKVM也有提供支持,但不了解支持程度以及稳定性等方面
IKVM对于2中状况比较有用: 一种Java中的一些项目没有.NET实现的,另一种是某些Java开源项目存在相应的.NET port,但Java的项目很活跃一直在完善更新,而.NET port则停滞了
项目使用的lisence值得考虑,IKVM.OpenJDK.*.dll使用GPL V2,其他的IKVM项目文件使用的lisence应该是BSD之类的 
下面拿StringTemplate做个测试
要求安装有JDK,在Windows环境变量中设置好JAVA_HOME路径(JDK目录),PATH中包含JDK的bin目录
下载安装IKVM,这个步骤非常简单,只需要从IKVM下载最新的bin distribution, 解压到一个目录,将IKVM的bin目录添加到系统环境变量PATH中

1. StringTemplate的Java测试项目
StringTemplate下载最新的Java StringTemplate。如果下载source进行编译的话,可以使用Ant编译(项目中有build.xml文件), 如果使用Eclipse,除了添加antlr的jar引用外,还需要使用antlr生成词法解析器、语法解析器、token等相关的java文件(在target\generated-sources目录下有已经生成好的java文件), 放入到src\org\antlr\stringtemplate\language目录下。编译项目后用Eclipse导出stringtemplate的jar文件
我用的版本为antlr-2.7.7.jar、stringtemplate-3.2.1.jar
用Eclipse建立测试项目,添加antlr-2.7.7.jar、stringtemplate-3.2.1.jar的引用,测试用的java文件如下:
Contact.java

public class Contact {
private String _name;
private String _email;
private int _score;

public Contact(String name, String email, int score){
this._name=name;
this._email=email;
this._score=score;
}
public String getName(){
return this._name;
}
public String getEMail(){
return this._email;
}
public int getScore(){
return this._score;
}
/*
* StringTemplate不支持在模板中做条件判断,因此下面在model中用属性实现
*/
public Boolean getIsLevel3(){
return this._score>1000;
}
public Boolean getIsLevel2(){
return this._score>200 && this._score<=1000;
}
public Boolean getIsLevel1(){
return this._score<=200;
}
}

sttest.java

import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.List;
import org.antlr.stringtemplate.*;
import org.antlr.stringtemplate.language.*;

public class sttest {
public static void main(String[] args) {
StringTemplateGroup group = new StringTemplateGroup("st-test"
, "E:\\Richie\\java\\workspace\\StringTemplateTest\\lib\\st"
, DefaultTemplateLexer.class);
StringTemplate st = group.lookupTemplate("contact_list");
// a simple attribute
st.setAttribute("simple_attribute", "Hello StringTemplate!");
// an object with properties as an attribute
Contact c = new Contact("Richie", "Richie-test@gmail.com", 100);
st.setAttribute("contact", c);
// collections test for Map
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("key1", 111);
map.put("key2", 222);
map.put("key3", 333);
st.setAttribute("items_hashtable", map);
// collections test for Array
int[] array = new int[3];
array[0]=1999;
array[1]=2888;
array[2]=3777;
st.setAttribute("items_array", array);
// collections test for List
List<Contact> list = new ArrayList<Contact>();
list.add(new Contact("Jacky Pan", "JackyPan-test@gmail.com", 1608));
list.add(new Contact("RicCC", "RicCC-test@gmail.com", 180));
list.add(new Contact("Richie", "Richie-test@gmail.com", 682));
st.setAttribute("items_list", list);

System.out.println(st.toString());
}
}

直接用Eclipse将其编译为Contact.class、sttest.class文件
测试用的StringTemplate文件如下:
contact_list.st

a simple attribute: $simple_attribute$
$!this is a comment!$
a contact instance:
{ Name="$contact.Name$", EMail="$contact.EMail$" }
Items - Map:
$!
Remarks:
The following ST syntax for maps (.NET IDictionary implementations) is not supported
by StringTemplate C# port (Version 3.2)
!$
map.item_name: { key1 - $items_hashtable.key1$ },{ key3 - $items_hashtable.key3$ }
iterator: $items_hashtable.keys: {{ $attr$ - $items_hashtable.(attr)$ }};separator=","$
Items - Array:
{ $items_array: {value|$value$};separator=","$ }
Items - List:
$items_list: row(seq="odd"), row(seq="even")$

row.st

<tr class="list-$seq$">
<td>$attr.Name$</td>
<td>$attr.EMail$</td>
<td>$attr.score$</td>
<td>$if(attr.IsLevel3)$Diamond$elseif(attr.IsLevel2)$Golden$else$Standard$endif$</td>
</tr>$\n$$! Remarks: the previous instruction will yield a line feed !$

为了方便,建立一个IKVMTest的目录,将antlr-2.7.7.jar、stringtemplate-3.2.1.jar、Contact.class、sttest.class文件都拷贝到IKVMTest目录中, 在IKVMTest中建立st目录,放入contact_list.st、row.st文件
在命令行进入IKVMTest目录,使用java sttest运行测试项目,结果如下:
     
StringTemplate C#的实现不太完善,上面java的测试项目中就有2个语法,目前StringTemplate C#的3.2版本不支持(或者是bug), 一个是对Map元素的访问方式(即$map_entry.(key)$语法),另一个是$elseif$指令,这个指令在不少情况下会出错。正好借用IKVM项目做这个测试

2. 动态方式运行Java项目
在命令行进入IKVMTest目录,使用ikvm sttest运行测试项目,结果与使用java.exe运行完全一样。也可以看到,ikvm sttest启动时有段时间CPU占用比较高, 此时IKVM在将相关class、jar文件动态编译为CIL代码
ikvm.exe的用法参考这里

3. 静态方式运行Java项目
首先,将antlr-2.7.7.jar转为.NET程序集
ikvmc -out:antlr-2.7.7.dll -target:library -platform:x86 antlr-2.7.7.jar
然后将stringtemplate-3.2.1.jar转为.NET程序集。因为StringTemplate引用了antlr,所以下面的命令必须使用-reference指定antlr的dll文件
ikvmc -out:stringtemplate-3.2.1.dll -target:library -platform:x86 -reference:antlr-2.7.7.dll stringtemplate-3.2.1.jar
最后,将Contact.class、sttest.class转为.NET的exe文件sttest.exe
ikvmc -out:sttest.exe -target:exe -platform:x86 -reference:antlr-2.7.7.dll -reference:stringtemplate-3.2.1.dll -main:sttest Contact.class sttest.class
上面的步骤会在我们测试目录中生成3个文件: antlr-2.7.7.dll、stringtemplate-3.2.1.dll、sttest.exe,这就是从jar、class转换过来的.NET托管程序集了

采用静态方式运行从java转换过来的项目时,需要引用IKVM相关的一些dll文件,我们可以将IKVM的dll注册到全局的GAC中,也可以把相关dll文件拷贝到我们的测试目录
这里我们直接从IKVM的bin目录,将IKVM.OpenJDK.Beans.dll、IKVM.OpenJDK.Charsets.dll、IKVM.OpenJDK.Core.dll、IKVM.OpenJDK.Security.dll、IKVM.OpenJDK.Text.dll、 IKVM.OpenJDK.Util.dll、IKVM.Runtime.dll这几个dll拷贝到我们的测试目录IKVMTest中(我猜测试项目只用到了这些dll),然后在命令行运行sttest.exe,可以看到运行结果与 前面java.exe的运行结果完全一致
ikvmc.exe的用法参考这里

4. 在.NET中使用Java项目
接下来我们用Visual Studio建立一个.NET的测试项目,来测试在.NET下面直接使用从Java转换过来的StringTemplate
我们手工把java的测试项目port成C#的实现。用Visual Studio新建一个IKVM.Test的Console项目,引用步骤 [3. 静态方式运行Java项目] 中生成的antlr-2.7.7.dll、 stringtemplate-3.2.1.dll这2个文件,引用IKVM.OpenJDK.Core.dll文件,项目代码如下:
Contact.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
namespace IKVM.Test
{
    using System;
    public class Contact
    {
        private String _name;
        private String _email;
        private int _score;
<br>
        public Contact(String name, String email, int score)
        {
            this._name = name;
            this._email = email;
            this._score = score;
        }
        public String getName()
        {
            return this._name;
        }
        public String getEMail()
        {
            return this._email;
        }
        public int getScore()
        {
            return this._score;
        }
        //StringTemplate不支持在模板中做条件判断,因此下面在model中用属性实现
        public Boolean getIsLevel3()
        {
            return this._score > 1000;
        }
        public Boolean getIsLevel2()
        {
            return this._score > 200 && this._score <= 1000;
        }
        public Boolean getIsLevel1()
        {
            return this._score <= 200;
        }
    }
}

Program.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
namespace IKVM.Test
{
    using System;
    using org.antlr.stringtemplate;
    using org.antlr.stringtemplate.language;
    class Program
    {
        static void Main(string[] args)
        {
            StringTemplateGroup group = new StringTemplateGroup("st-test"
                , ".\\st", typeof(DefaultTemplateLexer));
            StringTemplate st = group.lookupTemplate("contact_list");
            // a simple attribute
            st.setAttribute("simple_attribute", "Hello StringTemplate!");
            // an object with properties as an attribute
            Contact c = new Contact("Richie", "Richie-test@gmail.com", 100);
            st.setAttribute("contact", c);
            // collections test for Map
            java.util.Map map = new java.util.HashMap();
            map.put("key1", 111);
            map.put("key2", 222);
            map.put("key3", 333);
            st.setAttribute("items_hashtable", map);
            // collections test for Array
            int[] array = new int[3];
            array[0] = 1999;
            array[1] = 2888;
            array[2] = 3777;
            st.setAttribute("items_array", array);
            // collections test for List
            java.util.List list = new java.util.ArrayList();
            list.add(new Contact("Jacky Pan", "JackyPan-test@gmail.com", 1608));
            list.add(new Contact("RicCC", "RicCC-test@gmail.com", 180));
            list.add(new Contact("Richie", "Richie-test@gmail.com", 682));
            st.setAttribute("items_list", list);
            Console.Write(st.toString());
            Console.ReadKey();
        }
    }
}

编译后,将IKVM.Test.exe拷贝到我们的测试目录IKVMTest,运行结果仍然与前面java.exe运行的结果完全一致。可以看到,用这样的方式,对StringTemplate C#版本不支持的语法也能正确执行了

通过上面.NET的测试项目我们可以发现以下几点:
1. 基本数据类型(例如string、int、bool)通过IKVM直接实现互操作
2. 从java转换过来的CIL项目,在.NET中使用时需要遵循java的约定
   例如上面的Contact类,java下的StringTemplate采用反射读取属性值,使用的是java下约定,通过调用getName()、getEMail()等方法 读取,.NET中使用时我们要采用同样的约定才行,而不能定义成.NET的Property
3. JDK的class libraries需要使用IKVM.OpenJDK.Core等IKVM的实现
如果我们在项目中使用IKVM,可能需要通过一些封装手段分离client对IKVM的依赖,例如上面对StringTemplate的测试,我们可以通过接口封装的方法, 将IDictionary转换成java.util.Map,将IList转换成java.util.List等,避免客户端去引用java.util等这些命名空间。某些情况下这个分离可能比较烦

性能对比
性能测试使用的st模板以及给StringTemplate设置属性的代码都跟上面的代码一样,测试结果为
[Java版本] : [StingTemplate的C#版本] : [4. 在.NET中使用Java项目] = [1.5] : [1] : [16.2]
.NET的StringTemplate实现比java版本的性能好一些,在.NET中使用IKVM静态方式性能损失比较大。IKVM存在性能损失是肯定的,但这个差距太大了,可能对于不同项目结果会不一样吧

IKVM - 0.42.0.3 .NET平台上的Java实现的更多相关文章

  1. iOS 9 平台上 AFNetworking 框架 3.0 版本号解决的问题和问题解决

    iOS 9 平台上 AFNetworking 框架 3.0 版本号解决的问题和问题解决 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名- ...

  2. Android 8.0的平台上,应用不能对大部分的广播进行静态注册

    引言在Android 8.0的平台上,应用不能对大部分的广播进行静态注册,也就是说,不能在AndroidManifest文件对有些广播进行静态注册,这里必须强调是有些广播,因为有些广播还是能够注册的. ...

  3. centos7编译安装pure-ftpd-1.0.42

    一.下载 wget https://download.pureftpd.org/pub/pure-ftpd/releases/pure-ftpd-1.0.42.tar.gz 二.安装 tar xvf ...

  4. 【转】Tomcat7.0.42源代码运行环境搭建

    转自:http://tyrion.iteye.com/blog/1903608 以前看过Tomcat5的一部分源代码,当时只看了个大概的启动分析,后来看了<How Tomcat Works> ...

  5. Rudiments 0.42 发布,C++ 常用工具包 - 开源中国社区

    Rudiments 0.42 发布,C++ 常用工具包 - 开源中国社区 Rudiments 0.42 发布,C++ 常用工具包

  6. 在Foreda8中整合Apche httpd2.4.6和Tomcat7.0.42(使用tomcat-connectors-1.2.37)

    本地Apche httpd2.4.6(http://pan.baidu.com/share/link?shareid=4003375081&uk=34256769)和Tomcat7.0.42是 ...

  7. 在Foreda上安装apache-tomcat-7.0.42.tar.gz

    开发环境JDK和Tomcat应该和部署环境一致,要不容易出现奇奇怪怪的问题.所以Aspire机器上的Tomcat要装一个新版本了. 装Tomcat基本等于一个解压和移动的过程,确实简单. 第一步:解压 ...

  8. .NET平台上的Memcached客户端介绍

    早上接到一个任务,需要对Linux服务器的Memcached的update操作进行性能测试,我发现我是一个典型的“手里拿着锤子, 就把所有问题都当成钉子”的人.我第一个念头就是,上Memcached的 ...

  9. .NET平台上的Memcached客户端介绍(Memcached Providers)

    早上接到一个任务,需要对Linux服务器的Memcached的update操作进行性能测试,我发现我是一个典型的“手里拿着锤子,就把所有问题都当成钉子”的人.我第一个念头就是,上Memcached的官 ...

随机推荐

  1. JSTL之迭代标签库

    JSTL之迭代标签库 JSTL的全称是 Java Server Pages Standard Tag Library,翻译过来就是JSP标准标签库,它包含了在开发JSP页面时经常用到的一组标准标签.这 ...

  2. VS2010 EntityFramework Database First

    本文演练介绍如何使用实体框架进行 Database First 开发.通过 Database First,可以从现有数据库对模型进行反向工程处理.模型存储在一个 EDMX 文件(扩展名为 .edmx) ...

  3. 安装Apache Web 服务器软件

    Apache下载地址:http://pan.baidu.com/s/1kTKCEOn 1: 右击安装 2: 3: 4: 5:安装成功: 6:测试在浏览器地址栏输入:localhost; 会出现一个页面 ...

  4. gb2312编码提交url乱码解决

    gb2312编码提交url,服务器接收时出现乱码,用System.Web.HttpUtility.UrlDecode();解码 ,还是出现乱码,困老了我好长时间,终于在google上找到了解决办法. ...

  5. 让hyper-v调整console的大小

    在hyper-v中centos的console一直都是1024x768的分辨率,后来找到一种修改分辨率的解决方法 grubby --update-kernel=ALL --args="vid ...

  6. mysql查询语句分析 explain用法

    explain显示了mysql如何使用索引来处理select语句以及连接表.可以帮助选择更好的索引和写出更优化的查询语句. 使用方法,在select语句前加上explain就可以了,如: explai ...

  7. 深入分析 Java 中的中文编码问题(转)

    几种常见的编码格式 为什么要编码 不知道大家有没有想过一个问题,那就是为什么要编码?我们能不能不编码?要回答这个问题必须要回到计算机是如何表示我们人类能够理解的符号的,这些符号也就是我们人类使用的语言 ...

  8. TypeScript学习指南第二章--接口(Interface)

    接口(Interface) TypeScript的核心机制之一在于它的类型检查系统(type-checker)只关注一个变量的"模型(shape)" 稍后我们去了解这个所谓的形状是 ...

  9. Android常用的工具类(转)

    主要介绍总结的Android开发中常用的工具类,大部分同样适用于Java.目前包括HttpUtils.DownloadManagerPro.ShellUtils.PackageUtils.Prefer ...

  10. 图像混合学习。运用加权函数,学习opencv基础操作

               {          cout<<     }           {          cout<<     }       ,,logoImage.c ...