|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
还是要自己一点一点写代码,然后编译,改错再编译好那。还有最重要的是.net网页编程的编译环境非常好,你甚是不需要了解太多工具,对于简单的系统,你可以之了解一些语法就哦了。每次提到言语的时分我老是不由得骂Java是一学生产力低下,抱残守缺的言语——这估量要一向比及Java言语被JVM上的其他言语代替以后吧。JVM上今朝已有很多言语了:JRuby,Jython;另有一些特定于JVM平台的言语,如Scala和Groovy等等。可是,为何JVM上没有C#言语呢?按理说,这门和Java非常类似,却又壮大很多的言语更简单被Java程序员承受才对。您大概会说,Sun和微软是仇人,怎样大概将C#移植到JVM平台上呢?嗯,有事理,可是为何社区里也没有人这么做呢(要晓得JVM上其他言语都是由社区倡议的)?实在在我看来,这仍是遭到了手艺方面的限定。
泛型是Java和C#言语的主要特征,它使得程序员能够便利地举行范例平安的编程,而不必要像之前那样不休举行范例转换。比方,我们要在Java中写一个泛型字典的封装即可以这么做:- publicclassDictWrapper{privateHashMap<K,V>m_container=newHashMap<K,V>();publicVget(Kkey){returnthis.m_container.get(key);}publicvoidput(Kkey,Vvalue){this.m_container.put(key,value);}}
复制代码 看上往和C#并没有甚么区分,不是吗?不外,假如我们察看编译后天生的bytecode(相似于.NET平台上的IL),便会发明一丝奇奥的地方。利用javap-cDictWrapper失掉的了局是:- Compiledfrom"DictWrapper.java"publicclassjeffz.practices.DictWrapperextendsjava.lang.Object{publicjeffz.practices.DictWrapper();Code:0: aload_01: invokespecial #1;//Methodjava/lang/Object."<init>":()V4: aload_05: new #2;//classjava/util/HashMap8: dup9: invokespecial #3;//Methodjava/util/HashMap."<init>":()V12: putfield #4;//Fieldm_container:Ljava/util/HashMap;15: returnpublicjava.lang.Objectget(java.lang.Object);Code:0: aload_01: getfield #4;//Fieldm_container:Ljava/util/HashMap;4: aload_15: invokevirtual #5;//Methodjava/util/HashMap.get:(Ljava/lang/Object;)Ljava/lang/Object;8: areturnpublicvoidput(java.lang.Object,java.lang.Object);Code:0: aload_01: getfield #4;//Fieldm_container:Ljava/util/HashMap;4: aload_15: aload_26: invokevirtual #6;//Methodjava/util/HashMap.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;9: pop10: return}
复制代码 从bytecode中能够看出,个中并没有包括任何与K,V有关的信息。get/put办法的参数和前往值都是Object范例,乃至内置的HashMap也是云云。那末挪用DictWrapper的代码是怎样做到“强范例”的呢?比方:- publicstaticvoidmain(String[]args){DictWrapper<String,String>dict=newDictWrapper<String,String>();dict.put("Hello","World");Stringworld=dict.get("Hello");}
复制代码 它的bytecode即是:- publicstaticvoidmain(java.lang.String[]);Code:0: new #2;//classjeffz/practices/DictWrapper3: dup4: invokespecial #3;//Methodjeffz/practices/DictWrapper."<init>":()V7: astore_18: aload_19: ldc #4;//StringHello11: ldc #5;//StringWorld13: invokevirtual #6;//Methodjeffz/practices/DictWrapper.put:(Ljava/lang/Object;Ljava/lang/Object;)V16: aload_117: ldc #4;//StringHello19: invokevirtual #7;//Methodjeffz/practices/DictWrapper.get:(Ljava/lang/Object;)Ljava/lang/Object;22: checkcast #8;//classjava/lang/String25: astore_226: return}
复制代码 看到标号为22的那行代码没有?这条checkcast指令即是将上一句invokevirtual的了局转化为String范例——DictWrapper.get所前往的是个最一般不外的Object。
这即是Java言语的泛型完成——请注重我这里说的是Java言语,而不是JVM。由于JVM自己并没有“泛型”的观点,Java言语的泛型则完整是编译器的邪术。我们写出的泛型代码,现实上都是和Object对象在打交道,是编译器在帮我们省往了冗余的范例转换代码,以此包管了代码层面的范例平安。因为在运转时往除一切泛型的范例信息,因而这类泛型完成体例叫做TypeErasure(范例擦除)。
在.NET中则完整分歧,“泛型”是真逼真切落其实CLR层面上的功效。比方DictWrapper.Get办法在.NET上的IL代码即是:- .methodpublichidebysiginstance!TValueGet(!TKeykey)cilmanaged{.maxstack2.localsinit([0]!TValueCS$1$0000)L_0000:nopL_0001:ldarg.0L_0002:ldfldclass[mscorlib]...Dictionary`2...DictWrapper`2::m_containerL_0007:ldarg.1L_0008:callvirtinstance!1[mscorlib]...Dictionary`2::get_Item(!0)L_000d:stloc.0L_000e:br.sL_0010L_0010:ldloc.0L_0011:ret}
复制代码 您能够发明,.NET的IL便切实包括了TKey和TValue的范例信息。而在运转的时分,CLR会为分歧的泛型范例天生分歧的详细范例代码,这在我之前的文章中也有所说起。
那末,Java和C#两种泛型完成体例分离有甚么上风和优势呢?Java这类TypeErasure做法,最年夜的上风便在于其兼容性:即使利用了泛型,但最初天生的二进制文件也能够运转在泛型呈现之前的JVM上(乃至JDK中不必要增加分外的类库)——由于这里的泛型基本不触及JVM的变更。而.NET中的泛型必要CLR方面的“新才能”,因而.NET2.0的程序集是没法运转在CLR1.0上的——固然.NET1.0的程序集能够间接在CLR2.0上实行。而CLR完成体例的上风,便在于能够在运转时代表现出“模板化”的上风。.NET程序员都晓得,泛型能够节俭值范例的装箱和拆箱的开支,即使是援用范例也能够制止分外的范例转化,这些都能带来功能上的进步。
因而,在.NET社区常常会把Java的这类完成体例称之为“假泛型”,而同时也会有人辩驳到:泛型原本就是言语上的观点,完成分歧又有甚么干系,凭甚么说是“假”的呢?实在,因为得到了JVM的撑持,一些.NET平台上经常使用的,十分无效的开辟体例都难以使用在Java上。比方所谓的泛型字典:- publicclassCache<TKey,TValue>{publicstaticTValueInstance;}publicclassFactory{publicstaticstringCreate<TKey>(){if(Cache<TKey,string>.Instance==null){Cache<TKey,string>.Instance=//someexpensivecomputation}returnCache<TKey,string>.Instance;}}
复制代码 因为Cache<TKey>在运转时是个详细自力的范例,因而泛型字典是功能最高的存储体例,比O(1)工夫庞大度的哈希表还要凌驾很多。假如说这也只是运转方面的上风,那末这段代码中的“泛型工场”代码(即Factory.Create<SomeType>(),包含相似的Factory<T>.Create()这类)则是Java言语中没法完成的。这是由于TypeErasure的感化,在运转时JVM已损失了TKey如许的范例信息,而在.NET平台上,TKey则是Create<TKey>署名的构成部分。
TypeErasure酿成的限定另有很多,假如您是一个C#程序员,大概难以信任以下的Java代码都是分歧法的:- publicclassMyClass<E>{publicstaticvoidmyMethod(Objectitem){if(iteminstanceofE){//Compilererror...}Eitem2=newE();//CompilererrorE[]iArray=newE[10];//Compilererror}}
复制代码 因为JVM不供应对泛型的撑持,因而关于JVM上撑持泛型的言语,如Scala,这方面的压力就完整落在编译器身上了。并且,因为这些言语以JVM为底,TypeErasure会影响JVM平台上几近一切言语。以Scala为例,它的形式婚配语法能够用来判别一个变量的范例:- valuematch{casex:String=>println("ValueisaString")casex:HashMap[String,Int]=>println("ValueisHashMap[String,Int]")case_=>println("ValueisnotaStringorHashMap[String,Int]")}
复制代码 猜猜看,假如value变量是个HashMap[Int,Object]范例的对象,下面的代码会输入甚么了局呢?假如是C#或是F#如许运转在.NET平台上的言语,终极输入的必定是“Valueisnot...”。只惋惜,因为JVM的TypeErasure特征,以上代码输入的倒是“ValueisHashMap[String,Int]”。这是由于在运转时代JVM其实不包括泛型的范例信息,HashMap[K,V]便是HashMap,不管HashMap[String,Int]仍是HashMap[Int,Object]都是HashMap,JVM没法判别分歧泛型范例的汇合之间有甚么区分。不外还好,Scala编译器碰到这类情形会收回告诫,程序员能够懂得这些代码大概会呈现的“误解”。
因而,为何有IKVM.NET如许的项目能够将Java言语编译成.NET程序集(也能够将Java的jar包转化成.NET程序集),却没有项目将C#编译到JVM上(或是将C#程序集转化为jar包)。这是由于,JVM不敷以支持C#言语所必要的一切特征。而从运转时的两头代码角度来讲,JVMBytecode的才能也是.NETIL的子集——又有甚么举措能够将超集塞进它的子集呢?
别的,如CLR的值范例大概也很难间接落其实JVM上,这也是JVM上运转C#的又一拦阻。
固然,假如真要在JVM上完成完全的C#也并不是不成以。只需在JVM长进行一层封装(比方仍是就叫做CLR,CLRLanguageRuntime),必定能够满意C#的全体请求。可是这个价值太高,即便完成了这点大概也没甚么实践意义。而现实上,已有人在JVM上完成了一个x86摹拟器,那末又有是做不了的呢?其实不可,我们就在摹拟器上装一个Windows操纵体系,然后装一个Microsoft.NET,再……
本文来自:http://www.ckuyun.com/JeffreyZhao/archive/2010/02/22/why-not-csharp-on-jvm-type-erasure.html
赵
有了这样一个呼声:让java代替C语言成为基本语言。这些足以说明java简单易学的这个优点。其次,java的功能强大,前面我也提到了,EJB3.0的推出使java成为了大型项目的首选。 |
|