`

IKVM 编程武林之.NET派的北冥神功

阅读更多
在编程武林中,Java派成立较久底子雄厚,虽然掌门人Sun已经老态龙钟,镇山之技的Java语言已经被后进的新秀.NET派的C#压得喘不过气来,甚至有时候Sun老大还得跑到.NET派潜伏学艺。但是百足之虫,死而不僵,一众Java派的拥趸们自认虽然Java渐渐技不如人,但是Java派成立日久,从Java演化过来的七十二门绝技绝非武林暴发户.NET派所能比拟,其中几大支派如apache,springsource各有绝技,而衍生出的帮会、黑社会等等更是不计其数,.NET派望尘莫及。

然而江湖传言有不世神功叫北冥神功,“北冥有鱼,其名为鲲,鲲之大,不知其几千里也……”,能够容纳几千里的大鱼必定是非常广阔的海洋,因而北冥神功正是寓含了广大恢宏之意,也体现了神功的威力。“可以吸取他人的内力以供己用,是迅速提升功力的捷径。内力既厚,天下武功无不为我所用,犹如北冥,大舟小舟无不载,大鱼小鱼无不容。”

.NET派的几位高人闭关苦练,竟然悟出北冥神功,此神功后曰:IKVM.NET.

江湖后辈小子Ray Linn偶习此神功,得心得一二,不敢自珍,特此记之,以壮大我.NET门派,千秋万代,一统江湖。

那日Ray偶来到apache支派,却看到Apache弟子们各施绝技,好不热闹. Ray对Apache绝技手痒已久,想来得习IKVM.NET已有时日,斗胆上前叫阵。迎战者哪Apache派中的小弟子,江湖人称:commons.collection.

二人拳脚来去,Ray却懒得与之多动手脚,随即默念真言:
ikvmc -assembly:commons -target:library -version:1.0.0.0 commons-collections-3.2.1.jar  


collection陡然萎靡在地,想是一身内功尽被Ray所吸去,Apache派人等尽皆失色,“我等苦练十余载,内力尽为汝一夕取去”,莫敢上前。

Ray回转.NET派,试练collection的神功,借助IKVM.OpenJDK.Core之神器,神功即成,试演如下:

using System;

using org.apache.commons.collections;
using org.apache.commons.collections.functors;

namespace MyLib
{
    class Program
    {
        static void Main(string[] args)
        {
            String name = "Tim";
            Predicate nameJohn = new EqualPredicate( "John" );
            Predicate nameTim = new EqualPredicate( "Tim" );
            Predicate instanceString = new InstanceofPredicate(typeof(String) );
            Predicate instanceDouble = new InstanceofPredicate(typeof(Double));
            Console.Out.WriteLine( "Is Name John?: " + nameJohn.evaluate( name ) );
            Console.Out.WriteLine("Is Name Tim?: " + nameTim.evaluate(name));
            Console.Out.WriteLine( "Is this a String?: " + instanceString.evaluate( name ) );
            Console.Out.WriteLine( "Is this a Double?: " + instanceDouble.evaluate( name ) );

        }
    }
}



相较原有神功:
import org.apache.commons.collection.Predicate;
import org.apache.commons.collection.functors.*;
String name = "Tim";
Predicate nameJohn = new EqualPredicate( "John" );
Predicate nameTim = new EqualPredicate( "Tim" );
Predicate instanceString = new InstanceofPredicate( String.class );
Predicate instanceDouble = new InstanceofPredicate( Double.class );
// Testing all predicates for "Tim"
System.out.println( "Is Name John?: " + nameJohn.evaluate( name ) );
System.out.println( "Is Name Tim?: " + nameTim.evaluate( name ) );
System.out.println( "Is this a String?: " + instanceString.evaluate( name ) );
System.out.println( "Is this a Double?: " + instanceDouble.evaluate( name ) );


竟然绝无二致。

偌大Java江湖,从此为我.NET所用,哇哈哈。
分享到:
评论
50 楼 select*from爱 2010-06-08  
楼主有专业c#论坛推荐否?
49 楼 rdsuncn 2010-02-03  
互相抄袭以致如此境界,佩服
48 楼 wandou 2010-01-14  
不知道mono现在如何,以前我用它写了个demo,结果日期控件一到中文系统就崩溃了。
我用它编译了我写的一个项目,结果也不能正确运行,socket的行为与ms的不同。
47 楼 diddyrock 2010-01-11  
可是回头再想想,这个项目真的很有趣啊
也许java再不努力真的就是昨日黄花了
46 楼 diddyrock 2010-01-11  
lz文采真是好啊,东西也够深入。
但是作为一个java程序员,看到这种东西,第一眼的感觉就是愤怒啊,这不是硬要把鲜花插到牛粪上么。
45 楼 diddyrock 2010-01-11  
整个代码不超过1m?
44 楼 mathgl 2010-01-10  
我用 mono, ice来搭建一个实时车辆的系统,生产环境。 实际意义有用与否要试过才知道。
43 楼 mayang_lang 2010-01-06  
俺一直做J2EE开发,近来项目需要做做ASP.NET,第一次搜索就找到这么有趣味的帖子。呵呵……
42 楼 RednaxelaFX 2010-01-05  
icewubin 写道
Linux下开发桌面应用,QT是不是更适合?

我不知道哪个更好……假设某人系统上没有预先装好Mono,那Qt写的程序显然比Gtk#写的程序容易部署些(心理障碍小些)。不然的话……用“增强”的C++来写Qt程序跟用C#写Gtk#的程序哪个好貌似更多是个人喜好问题?或者像Miguel所期待的那样,以后能利用强化的Moonlight + out-of-browser能力用XAML/C#写Linux桌面应用也会是个有趣的选择。
41 楼 RednaxelaFX 2010-01-05  
iaimstar 写道
我想知道fx你这种不出三句话有两个链接的好习惯是怎么养出来的。。

我不想回头被“求详细”……顺手留下链接免得大家找起来烦。

iaimstar 写道
也就是说除了好玩和好看,目前还没有什么实际意义

我留的链接里不是颇有些实际有很多人用的东西嘛,至少Second Life的用户就很多……还要么,BansheeF-SpotDekiWiki(<< 部署实例)?
40 楼 iaimstar 2010-01-05  
我想知道fx你这种不出三句话有两个链接的好习惯是怎么养出来的。。
RednaxelaFX 写道

·熟悉.NET开发的人希望开发Linux、Mac等平台上的程序 -- Mono/Portable .NET
·熟悉.NET开发的人希望开发iPhone、Wii、PS3等平台上的程序 -- Mono
·熟悉.NET的人希望利用Java的优秀的服务器 -- Grasshopper (看这里的评论)
·熟悉.NET技术但希望降低软件成本,希望在Linux上部署ASP.NET应用 -- Mono
·熟悉Java的人希望迁移到.NET平台上 -- IKVM/Ja.NET
·.NET程序员希望以很小的成本使用Java已有的丰富的库 -- 同上
。。。

也就是说除了好玩和好看,目前还没有什么实际意义
39 楼 icewubin 2010-01-05  
Linux下开发桌面应用,QT是不是更适合?
38 楼 RednaxelaFX 2010-01-05  
liudun 写道
mono和ikvm有多大的实际意义?

要是用广告词语气的话,我会说实际意义在于“leverage”,在不同的场景下延用已掌握的技术/技巧。例如说:
·熟悉.NET开发的人希望开发Linux、Mac等平台上的程序 -- Mono/Portable .NET
·熟悉.NET开发的人希望开发iPhone、Wii、PS3等平台上的程序 -- Mono
·熟悉.NET的人希望利用Java的优秀的服务器 -- Grasshopper (看这里的评论
·熟悉.NET技术但希望降低软件成本,希望在Linux上部署ASP.NET应用 -- Mono
·熟悉Java的人希望迁移到.NET平台上 -- IKVM/Ja.NET
·.NET程序员希望以很小的成本使用Java已有的丰富的库 -- 同上
  不止一次见到有人拿JRubyRhino之类的Java实现的脚本引擎用IKVM放到.NET上跑了……人家就是有这乐子
·希望在程序中嵌入高级语言运行环境作为脚本或高级开发语言 -- Mono (看Second Life或者Unity
  Mono虽然比不上一些主流的JVM先进,但它的执行速度好歹还是比CPython和CRuby这些脚本引擎快多了,自带的库也很丰富(同时也可根据需要裁剪),甚至有对SIMD、continuation等的支持
·希望在资源极度受限的环境中用类型安全的语言、在托管环境中开发 -- Portable.NET (看这里提到的几个实例)
·Linux开发者希望借用.NET的理念在Linux上做开发 -- Mono
  这是Miguel创始Mono计划的初衷,为了在Linux上能更方便的开发桌面应用之类的;他觉得C做这种事情太麻烦了。
  好吧现在的话用Vala也可以……
·自由软件世界的同志不愿意看到微软树立了行业标准(CLI、C#)而大摇大摆 -- Portable .NET

随便举了些场景的例子。大家都有自己的算盘,有自己的需求;如果某东西的成熟度正好能满足场景与需求,那就拿来用呗 >_<b
37 楼 liudun 2010-01-05  
高手很多啊。

mono和ikvm有多大的实际意义?
36 楼 RednaxelaFX 2009-12-30  
icewubin 写道
我没有什么证据,随口说一些功能上的例子吧,例如很好用的java.util.concurrent.atomic.AtomicInteger类,底层使用了不开源的sun.misc.Unsafe(未必不开源,实际上是我没花时间找,默认的JDK中貌似没有这个类的源代码),如果对应到CLR中不知能否正确实现AtomicInteger类的功能。

基本上整个JDK都开源了,像Unsafe这么重要的类型要是不开源那也未免太不厚道了 XD

以java.util.concurrent.atomic.AtomicInteger举例:
AtomicInteger.compareAndSet()的实现如下:
public final boolean compareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

该实现依赖于sun.misc.Unsafe。在class文件被加载时,sun.misc.Unsafe.compareAndSwapInt()就被识别为intrinsic方法了。
vmSymbols.hpp
do_intrinsic(_compareAndSwapInt,        sun_misc_Unsafe,        compareAndSwapInt_name, compareAndSwapInt_signature, F_RN) \
do_name(     compareAndSwapInt_name,                          "compareAndSwapInt")                                   \
do_signature(compareAndSwapInt_signature,                     "(Ljava/lang/Object;JII)Z")                            \


在解释模式下,Unsafe.compareAndSwapInt()被实现为:
unsafe.cpp
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
  UnsafeWrapper("Unsafe_CompareAndSwapInt");
  oop p = JNIHandles::resolve(obj);
  jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);
  return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
UNSAFE_END

通用的Atomic::cmpxchg()实现为:
atomic.cpp
unsigned Atomic::cmpxchg(unsigned int exchange_value,
                         volatile unsigned int* dest, unsigned int compare_value) {
  assert(sizeof(unsigned int) == sizeof(jint), "more work to do");
  return (unsigned int)Atomic::cmpxchg((jint)exchange_value, (volatile jint*)dest,
                                       (jint)compare_value);
}

在Windows/x86(非AMD64)上的实现为:
inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value) {
  // alternative for InterlockedCompareExchange
  int mp = os::is_MP();
  __asm {
    mov edx, dest
    mov ecx, exchange_value
    mov eax, compare_value
    LOCK_IF_MP(mp)
    cmpxchg dword ptr [edx], ecx
  }
}

本来是可以直接用Win32 API中的InterlockedCompareExchange(),不过Sun的工程师觉得这个函数在Win95上跑不了所以就干脆自己写汇编了。
这里的重点就是x86的cmpxchg指令。这是一种compare-and-swap(CAS)系的指令。

在编译模式下,JIT会识别出对Unsafe.compareAndSwapInt()的调用。其中-client编译器(也称为C1)在x86上会通过下面一系列调用最终生成cmpxchg指令:
c1_LIRGenerator_x86.cpp
else if (type == intType)
  __ cas_int(addr, cmp.result(), val.result(), ill, ill);

c1_LIR.cpp
append(new LIR_OpCompareAndSwap(lir_cas_int, addr, cmp_value, new_value, t1, t2));

c1_LIRAssembler_x86.cpp
else if (op->code() == lir_cas_int) {
  __ cmpxchgl(newval, Address(addr, 0));
}

assembler_x86.cpp
// The 32-bit cmpxchg compares the value at adr with the contents of rax,
// and stores reg into adr if so; otherwise, the value at adr is loaded into rax,.
// The ZF is set if the compared values were equal, and cleared otherwise.
void Assembler::cmpxchgl(Register reg, Address adr) { // cmpxchg
  if (Atomics & 2) {
     // caveat: no instructionmark, so this isn't relocatable.
     // Emit a synthetic, non-atomic, CAS equivalent.
     // Beware.  The synthetic form sets all ICCs, not just ZF.
     // cmpxchg r,[m] is equivalent to rax, = CAS (m, rax, r)
     cmpl(rax, adr);
     movl(rax, adr);
     if (reg != rax) {
        Label L ;
        jcc(Assembler::notEqual, L);
        movl(adr, reg);
        bind(L);
     }
  } else {
     InstructionMark im(this);
     prefix(adr, reg);
     emit_byte(0x0F);
     emit_byte(0xB1);
     emit_operand(reg, adr);
  }
}

在else分支中,生成的0x0F 0xB1就是cmpxchg

在.NET上,对应的功能由System.Threading.Interlocked提供。Unsafe.compareAndSwapInt()对应的是System.Threading.Interlocked.CompareExchange()。底下依赖的x86指令也同样是cmpxchg。
Interlocked类在.NET 1.0的时候就已经有了,而AtomicInteger是Java 5新增的,这个嘛……
35 楼 ray_linn 2009-12-30  
icewubin 写道
RednaxelaFX 写道
JVM的性能进步对上层应用的影响不可谓不大。其中一个有趣的侧面是Sun的javac:从JDK 1.3开始它就会忽略-o编译开关——Sun认为在Java源码到JVM字节码过程中的优化没多少必要,反正HotSpot能提供足够优化。虽说这个设计到底是不是真的合理还可以商榷……

JVM的实现自然也会影响到库的实现。之前正好记过一篇关于反射调用方法的一个log,也算是能扯上关系。

还是你对VM相关的技术更了解,我只是知道,拍脑袋认为的一些个人观点而已。

我没有什么证据,随口说一些功能上的例子吧,例如很好用的java.util.concurrent.atomic.AtomicInteger类,底层使用了不开源的sun.misc.Unsafe(未必不开源,实际上是我没花时间找,默认的JDK中貌似没有这个类的源代码),如果对应到CLR中不知能否正确实现AtomicInteger类的功能。

还有像在多核CPU下transient关键字在JVM自己的不同版本中实现都不一样,不知道CLR会如何处理。




System.Threading.Interlocked.CompareExchange() = sun.misc.Unsafe.compareAndSwapInt().

AtomicInteger.incrementAndGet()=Interlocked.Increment(ref foo);

通过C#的等价替代,很自然就实现java基础类库的CLR版,(由于IKVM根本不依赖于JDK,所以必须提供自己的CLR版java类库以便让自己的java应用引用)
34 楼 icewubin 2009-12-29  
RednaxelaFX 写道
JVM的性能进步对上层应用的影响不可谓不大。其中一个有趣的侧面是Sun的javac:从JDK 1.3开始它就会忽略-o编译开关——Sun认为在Java源码到JVM字节码过程中的优化没多少必要,反正HotSpot能提供足够优化。虽说这个设计到底是不是真的合理还可以商榷……

JVM的实现自然也会影响到库的实现。之前正好记过一篇关于反射调用方法的一个log,也算是能扯上关系。

还是你对VM相关的技术更了解,我只是知道,拍脑袋认为的一些个人观点而已。

我没有什么证据,随口说一些功能上的例子吧,例如很好用的java.util.concurrent.atomic.AtomicInteger类,底层使用了不开源的sun.misc.Unsafe(未必不开源,实际上是我没花时间找,默认的JDK中貌似没有这个类的源代码),如果对应到CLR中不知能否正确实现AtomicInteger类的功能。

还有像在多核CPU下transient关键字在JVM自己的不同版本中实现都不一样,不知道CLR会如何处理。
33 楼 RednaxelaFX 2009-12-29  
ray_linn 写道
幸存者 写道
ray_linn 写道

这里我想到如果实现动态ngen--似乎更美妙,只ngen到被调用的那些方法,可以称为动态ngen或者静态hotspot

动态ngen?和jit有什么区别?除非把native code保存到磁盘上,那倒算是有区别,不过那样似乎就把ngen和jit的缺点都占了——既不能动态优化,又必须在运行时编译。


我的意思是对于GAC里的类,替换被调用的IL为native code,这样之后的所有调用都是native code,而未被调用的IL则继续保持原来的格式。

谈到这个话题不得不提JTL式的编译器……just-too-late 
32 楼 RednaxelaFX 2009-12-29  
JPython已经不叫JPython很久了……现在是Jython。该计划一直半死不活,到去年才开始重获生机开始快速发展。看看SourceForge中间有些版本是断的……
IronPython是从2.0开始转用DLR的(或者说把DLR剥离出来的)。剥离出来的DLR原本就是IronPython 1.x的一部分,独立出来之后为什么性能会降低……?随着经验的积累,在DLR的tuning也比IronPython 1.x的时代要好了。IronPython 2.6的性能比IronPython 2.0的性能……well有些地方因为实现的功能更复杂了所以……那不是DLR的错嗯。至少IronPython 2.6的启动速度比2.0快多了,在DLR的解释器的协助下。

DLR里的很多优化技巧也跟源于Smalltalk/Self系的技术,跟HotSpot的有相似的源头;像是callsite caching、hidden class等……用起来也很方便。
31 楼 ray_linn 2009-12-29  
幸存者 写道
ray_linn 写道

这里我想到如果实现动态ngen--似乎更美妙,只ngen到被调用的那些方法,可以称为动态ngen或者静态hotspot

动态ngen?和jit有什么区别?除非把native code保存到磁盘上,那倒算是有区别,不过那样似乎就把ngen和jit的缺点都占了——既不能动态优化,又必须在运行时编译。


我的意思是对于GAC里的类,替换被调用的IL为native code,这样之后的所有调用都是native code,而未被调用的IL则继续保持原来的格式。

相关推荐

    IKVM.NET 8.1.15

    IKVM.NET是一个开源项目,由Glenn Block创建,它的全称是"IKVM - Java for .NET"。这个项目的主要目标是将Java平台的核心部分移植到.NET Framework上,使得Java程序能够在.NET环境中运行。IKVM.NET 8.1.15是该项目的...

    IKVM7.3.4830.0,将java的jar包转换为.dll控件,以使.NET可以使用

    http://weblog.ikvm.net/default.aspx 解压ikvmbin ,并将%IKVM_HOME%\bin添加到path中。此处的%IKVM_HOME%是指解压后ikvm的主目录。 将java的jar包转换为.dll控件 使用的命令:ikvmc -out:XXXX.dll XXXX.jar ...

    IKVM-8.8.0-bin-net6.0

    IKVM(Java for .NET)是一个开源项目,它实现了Java虚拟机(JVM)和Java类库,使得Java程序可以在.NET环境中运行。标题中的"IKVM-8.8.0-bin-net6.0"指的是该版本是专为.NET 6框架优化的IKVM发布版,意味着它可以...

    IKVM.NETv8.1

    Java 8引入了许多重要的新特性,如lambda表达式、方法引用来支持函数式编程,以及Stream API,这些都可以通过IKVM.NET在.NET环境中使用。 在实际应用中,IKVM.NET的使用流程大致如下: 1. 下载并安装IKVM.NET的相应...

    IKVM7.4.5196.0,将java的jar包转换为.dll控件,以使.NET可以使用

    http://weblog.ikvm.net/default.aspx 解压ikvmbin ,并将%IKVM_HOME%\bin添加到path中。此处的%IKVM_HOME%是指解压后ikvm的主目录。 将java的jar包转换为.dll控件 使用的命令:ikvmc -out:XXXX.dll XXXX.jar ...

    ikvm学习入门 .net与java程序互访

    IKVM(IronJava Virtual Machine)是一个开源项目,它实现了Java虚拟机(JVM)和Java类库,并将它们集成到.NET Framework中。这样,开发者可以在.NET环境中运行Java应用程序,同时也能利用.NET平台的特性和资源。这...

    ikvm-7.2.4630.5.rar

    IKVM.NET是一个开源项目,由Glenn Block创建,它的全称是"Java for .NET",旨在为.NET Framework提供一个完整的Java虚拟机(JVM)实现。这个项目的核心目标是让Java应用程序能够在Microsoft的.NET环境中无缝运行,...

    ikvmbin-8.1.5717.0版本 jar包转dll

    IKVM是一种开源项目,全称为“IKVM.NET”,它是一个.NET框架的实现,允许Java应用程序在.NET环境中运行。IKVM的核心功能是将Java字节码转换为.NET中间语言(IL),使得Java类库可以在.NET平台上无缝使用。在这个场景...

    IKVM最新版.rar

    IKVM(Java for .NET)是一款开源项目,由Jeroen Frijters开发,它将Java虚拟机(JVM)和Java类库实现为.NET框架的一部分。这个工具允许.NET开发者利用Java库,将它们转换为.NET组件,进而可以在C#等.NET语言中直接...

    IKVM-8.2.4630.5.rar

    IKVM(Java to .NET)是一个开源项目,它实现了Java虚拟机(JVM)和Java类库,使得Java程序可以在Microsoft.NET平台上运行。这个“IKVM-8.2.4630.5.rar”压缩包包含的是IKVM的一个特定版本,即8.2.4630.5,它提供了...

    java2.net_ikvm8.1.5717.0

    jar包转换成.net的工具,包含ikvmsrc-8.1.5717.0.zip、ikvmbin-8.1.5717.0.zip、ikvmbin-7.2.4630.5.zip三个文件。...IKVM.NET是一个针对Mono和微软.net框架的java实现,其设计目的是在.NET平台上运行java程序。

    IKVM.NET详细信息

    IKVM.NET是一个开源项目,由Glenn Block创建,它的全称是"I Know VM for .NET",是一个将Java虚拟机(JVM)和Java类库移植到.NET Framework的实现。这个项目的主要目标是允许.NET开发者能够使用Java库,同时也能让...

    ikvm资源及测试包

    IKVM是一种开源项目,全称为"IKVM.NET",它实现了Java虚拟机(JVM)并将其集成到.NET Framework中,使得.NET开发者可以利用Java库和程序在C#等.NET语言中运行。这个资源包“ikvm资源及测试包”显然是针对想要在C#...

    ikvm-7.2.4630.5.zip

    IKVM.NET的主要功能之一是允许.NET开发者利用Java类库,比如在描述中提到的"hanlp.jar",这是一个著名的中文分词和自然语言处理库。通过IKVM.NET,开发者无需将代码迁移到Java环境中,可以直接在C#或其他.NET语言的...

    ikvm8支持jdk8.zip

    IKVM.NET是一个开源项目,由Glenn Block创建,它的全称是"IKVM: Java for .NET"。这个项目的主要目标是实现一个Java虚拟机(JVM)和Java类库的.NET Framework版本,使得Java代码可以在.NET环境中运行,同时也允许...

    .net调用java IKVM-8.1.5717.1

    .NET调用Java IKVM-8.1.5717.1是一个技术组合,它允许.NET Framework应用程序调用和利用Java代码和库。IKVM(Java for .NET)是一个开源项目,由Ganesh Venkatraman开发,其主要目标是实现Java虚拟机(JVM)和Java ...

    ikvm-8.1.5717.0

    4. **部署灵活性**:由于ikvm将Java代码编译为.NET IL,因此,Java应用程序可以作为.NET组件进行部署,无需在目标机器上安装完整的JVM。 5. **开源社区支持**:ikvm是开源项目,由全球开发者共同维护和改进。这意味...

    ikvmsrc-8.1.5717.0_C#_ikvm8_

    标题“ikvmsrc-8.1.5717.0_C#_ikvm8_”提及的是IKVM库的一个版本,这是一个开源项目,它允许在.NET平台上运行Java应用程序和库。IKVM将Java虚拟机(JVM)和Java Class Library的实现转化为.NET Framework兼容的组件...

    ikvmbin-8.1.5717.0 IKVM.NET

    基于.NET的Java虚拟机意味着我们可以让Java程序跑在.NET上,可以通过虚拟机这个中介让Java程序和.NET应用程序一起协同工作。更难能可贵的是,IKVM同时支持微软的.NET Framework 和 Mono。

    IKVM.GNU.Classpath

    这个项目的核心是IKVM.NET,一个实现了Java虚拟机(JVM)和大部分Java核心类库的.NET版本。IKVM这个名字是"Java for .NET"的缩写,它的目标是将Java技术融入.NET世界,使开发者能够利用.NET的优势来开发和运行Java...

Global site tag (gtag.js) - Google Analytics