节选自《C++、Java/C#之比较》http://dev.firnow.com/course/3_program/c++/cppsl/2008520/117228.html 使用指针,由程序员根据需要分配、访问内存,程序运行时动作明确直接没有额外的处理步骤,程序的执行效率就高,但若程序员忘了释放内存或释放内存的策略不够周全,就会产生不可预知的问题,而且这种问题往往是比较严重。 不使用指针,并不意味着内存的分配、访问与释放不须处理,只不过是这些工作由编译器生成的通用“内存管理器”完成了,因此程序执行时,必须增加额外的内存管理动作,所以执行效率相对上种方式而言有所下降。由于“内存管理器”的运作是基于业内专业人士制定的比较完善内存管理机制,因而安全程度较高。但实际上,由于内存的分配、访问、使用、释放的情况比较复杂,这种安全性并不是100%的。也就是说安全的保证是由“另外的人”负责的,这种情况下,一旦出现问题,你无法查清问题所在,或即使你查清问题所在,也无法纠正。 好了,关于指针,一边是100%的效率、60%的安全性、100%的自由,一边是60%的效率、99%的安全性、100%枷锁,你选择吧。我想对于“高手”而言,自信也罢、固执也罢,选择指针是他们骨子里自由与冒险精神的决定。 “是生,是死——这是一个值得考虑的问题。”——但不要丧失了行动的能力。 下文引自《Java与C#的区别(语言级别)》http://wantsong.javaeye.com/blog/28769 Java与C#的区别(语言级别) 可以到这里详细了解Java与C#的区别,The C# Programming Language for Java Developers。 我将其整理了下,大致列在下面: 1. 源文件方面。C#可以在一个.cs 文件中。出现多个name sapce(命名空间,有些类似于pacakage),并定义多个类。C#包含有预处理指令。 2. 数据类型方面。 a) C#定义了struct(结构),不能是抽象的,也不能被继承,是值类型的。 b) C#没有基本类型的概念,全部是面向对象的类型,int是Int32的简写。 c) 在Java中const是保留字,final与C#中的const意思相同,C#中还有readonly允许运行时赋初值。 d) 字符串比较,C#中可以用=比较值,与Java一样用StringBuffer来减少内存开销。 3. 运算符方面。C#增加了Checked和Unchecked以绕过编译错误。比如“把一个long付给int32 ,如果高32为零 则不会出错,否则会有溢出错误,unchekced就是告诉编译器不要去管溢出,尽你可能转化” 4. 分支语句方面。在Java中goto是保留字。C#中switch中的case不会顺序执行,末尾必须有break或者goto关键字。 5. 循环语句好像没有什么不同的。 6. 访问修饰符方面。在范围放main,C#增加了internal和protected internal,前者表示只能从当前程序集内可见,即可以在编译时可Assembly的DLL或EXE,类似于JAR;后者表示对当前程序集或者从此包含类继承的类可见。Sealed相当于Java中的final关键字。 7. 方法方面。与Java相同,只有基本类型通过值传递,其他都是传递引用。不过C#也可以以引用的方式传递基本类型,利用ref关键字。而out关键字有些类似于Oracle存储过程,与ref的区别在于:方法忽略out参数初始值,方法必须为out参数赋值。 8. 属性方面。Getter和Setter的写法不太一样。 9. 继承方面。C#增加了base关键字以指向父类。C#中父类方法中具有virtual关键字的才可以被子类重写,重写时还需要声明override。与抽象类相同,abstract关键字也必须被override重写。C#中的接口不能声明常量,接口的属性只是表示Getter或Setter。 10. 事件。Java中没有(Java通过实现自定义侦听器类执行事件)。C#定义了类似于函数指针的委托来实现事件。 11. 运算符重载。Java中无。运算符重载必须为类的静态方法,重载==,其他判等操作也必许重载。 12. 异常方面。与Java非常相似,只是没有throws关键字,无须截获异常(当然要在程序主入口去截)。 13. C#增加了索引器,可以象访问数组一样访问类或结构。个人感觉就是少些几个字而已,还造成一定的困扰。 14. C#的Attribute要比Java的Annotation强很多。不过加上AOP后,这种动态功能Java也不错了。 15. 在C#中也可以直接使用指针,开辟或者回收内存,只是要使用两个关键字unsafe和fixed。 引用自《c#,C++,Java比较》http://read.newbooks.com.cn/info/137063.html 1:纯对象导向语言 C# 和 java 都是纯对象导向语言,C++ 非纯对象导向语言。 2:强制型态检查 C# 和 java 都强制进行型态检查,C++ 则较宽松。 3:宏 C# 和 java 都不支持宏,C++ 支持宏。 4:Template C# 和 java 都不支持 template,C++ 支持 template。 5:多重继承 C# 和 java 都不支持多重继承,且都支持 interface,C++ 支持多重继承。 6:指针 C# 和 java 都不支持指针,C++ 支持指针。(不过,C# 允许在 unsafe code 内使用指针) 7:内存管理 C# 和 java 都支持垃圾收集。C++ 不支持垃圾收集。 8:虚拟机器 C# 和 java 都需要虚拟机器,C++ 不需要虚拟机器。Java 的执行档是中间码,叫做 bytecode,透过 java Runtime Environment(即 JRE)来执行;C# 的执行档也是中间码,叫做 managed code,透过 NGWS Runtime 来执行。除了 java,你也可以用其它程序语言(例如 Ada、Python)来作出 bytecode。除了 C#,你也可以用其它程序语言(例如 Visual Basic、C++)来作出 managed code。 9:Namespace C# 和 java 都支持阶层式的 namespace,但 C++ 只支持单层的 namespace。Java 的 namespace 称为 package,C# 的 namespace 就称为 namespace。Java 和 C# 都使用「.」当作 namespace 的符号,而 C++ 使用「::」。 10:Platform-Independent Type C# 和 java 都使用 Platform-Independent Type,C++ 的 type 会受到平台的影响。 11:使用 Wrapper 包装基本型态 C# 和 java 都支持将基本型态包装成对象,在 java 叫做 wrapper,在 C# 则是叫做 box。 12:boolean != integer C# 和 java 都不允许把整数当布尔值用,C++ 则允许。 13:access modifier C# 和 java 都支持四种等级的 access modifier,包括 public、protected、private、default/internal;C++ 只支持 public、protected、private。Java 的 default(不写)指的就是只针对同一个 package 开放,正好就是 C# 的 internal。 14:变量初始化 C# 和 java 都规定不可使用未初始化的变量,C++ 则完全没有这方面的限制。Java 和 C# 的编译器都会主动帮未初始化的 field/data member 设定初始值,C++ 则不然。 15:转型 C# 和 java 都规定基本型态和 reference 型态不能互转。 16:数组边界检查 C# 和 java 都会主动进行数组边界检查,C++ 则不然 17:呼叫 Native Code C# 和 java 都支持呼叫 native code。Java 透过 JNI(Java Native Interface);C# 透过 PInvoke(Platform Invocation Service) 18:Metadata C# 和 java 的中间码都包含有类别的 metadata,而 C 语言则是独立在 header file。 19:中间码指令 C# 的 IL 中间码指令和 java 的 bytecode 指令非常类似,有的甚至一样。 20:例外处理 C# 和 java 都支持 try/catch/finally,但 C++ 只支持 try/catch。 较细节,出处未知 c#与java的区别 1.属性: java中定义和访问均要用get和set方法,可以不成对出现。 c#中是真正的属性,定义时get和set必须同时出现,房问时用.号即可。不用get,set 2.对象索引 就是对象数组 public Story this [int index] 3.C#中,不用任何范围修饰符时,默认的是protect,因而不能在类外被访问. 4.因为JAVA规定,在一个文件中只能有一个public类,而且这个类的名称必须与文件名一模一样,这是一个区别 5.在C#中,它是以Main方法来定位入口的.如果一个程序中没有一个名为Main的方法,就会出"找不到入口的错误".不要把Main写成main哟 6.C#预定义的简单数据类型比Java多。例如,C#有unit,即无符号整数 7.忘掉Java中的static final修饰符。在C#中,常量可以用const关键词声明 C#的设计者还增加了readonly关键词,readonly域只能通过初始化器或类的构造函数设置 8.公用类的入口点:c#是可以对Main进行重载(java中是main),允许有int返回值和空参数的Main 9.在Java中,switch语句只能处理整数。但C#中的switch语句不同,它还能够处理字符变量。请考虑下面用switch语句处理字符串变量的C#代码 10.C#没有>>>移位操作符 11.goto关键词: Java不用goto关键词。在C#中,goto允许你转到指定的标签。不过,C#以特别谨慎的态度对待goto,比如它不允许goto转入到语句块的内部。在Java中,你可以用带标签的语句加上break或continue取代C#中的goto。 12.int[] x = { 0, 1, 2, 3 }; int x[] = { 0, 1, 2, 3 }; 但在C#中,只有第一行代码合法,[]不能放到变量名字之后。 13.与Java不同的是,C#允许为名称空间或者名称空间中的类指定别名: using TheConsole = System.Console; 14.在Java中,包的名字同时也是实际存在的实体,它决定了放置.java文件的目录结构。在C#中,物理的包和逻辑的名称之间是完全分离的 .NET中包的实体称为程序集(Assembly)。每一个程序集包含一个manifest结构。manifest列举程序集所包含的文件,控制哪些类型和资源被显露到程序集之外,并把对这些类型和资源的引用映射到包含这些类型与资源的文件。程序集是自包含的,一个程序集可以放置到单一的文件之内,也可以分割成多个文件。.NET的这种封装机制解决了DLL文件所面临的问题,即臭名昭著的DLL Hell问题。 15.在Java中,java.lang包是默认的包,C#中不存在默认的包 16.C#中的访问修饰符与Java中的基本对应,但多出了一个internal。简而言之,C#有5种类型的可访问性,如下所示: public:成员可以从任何代码访问。 protected:成员只能从派生类访问。 internal:成员只能从同一程序集的内部访问。 protected internal:成员只能从同一程序集内的派生类访问。 private:成员只能在当前类的内部访问。 17.由于C#中不存在final关键词,如果想要某个类不再被派生,你可以使用sealed关键词 18.与Java不同,C#中的接口不能包含域(Field)。 另外还要注意,在C#中,接口内的所有方法默认都是公用方法。在Java中,方法声明可以带有public修饰符(即使这并非必要),但在C#中,显式为接口的方法指定public修饰符是非法的。例如,下面的C#接口将产生一个编译错误。 19.C#中的is操作符与Java中的instanceof操作符一样,两者都可以用来测试某个对象的实例是否属于特定的类型。在Java中没有与C#中的as操作符等价的操作符。as操作符与is操作符非常相似,但它更富有“进取心”:如果类型正确的话,as操作符会尝试把被测试的对象引用转换成目标类型;否则,它把变量引用设置成null。 20.C#仍旧保留了C++的内存手工管理方法,它适合在速度极端重要的场合使用,而在Java中这是不允许的 21.在C#中,所有的异常都从一个名为Exception的类派生 22.枚举器即enum类型(java无),把它作为一个变量值的类型使用,从而把变量可能的取值范围限制为枚举器中出现的值。 23.结构(Struct)与类很相似,而结构是一种值类型,它存储在栈中或者是嵌入式的,结构可以实现接口,可以象类一样拥有成员,但结构不支持继承 24.属性声明语法的第一部分与域声明很相似,第二部分包括一个set过程和/或一个get过程 25.传值方式: 在java中简单数据类型的值传参时,都以传值方式; 在c#中如果加ref则会以引用的方式传值(方法内部改变该参数,则外部变量一起跟着变); 加out与ref基本相同,但out不要求参数一定要初始化. 26.c#保留了指针。unsafe 27.代理:代理(delegate)可以看作C++或者其他语言中的函数指针 代理用来封装可调用方法。你可以在类里面编写方法并在该方法上创建代理,此后这个代理就可以被传递到第二个方法。这样,第二个方法就可以调用第一个方法。 代理是从公共基类System.Delegate派生的引用类型。定义和使用代理包括三个步骤:声明,创建实例,调用。代理用delegate声明语法声明。 更细致的 C#与JAVA之比较(作者Yesky) C#、Java之比较 很多人说C#是微软用来和Java抗衡的武器,因为二者在很大程度上有着惊人的相似 ,尽管如此,两者不同的地方也很多,所谓“于细微处见差异”。那么两者的相似和区 别都在什么地方呢?我们从今天开始,会从各个角度来对比C#和Java的特点,希望能对 正在学习、使用C#的朋友有所帮助。 1、C#和.NET平台的概貌 2000年6月,微软发布C#语言和.NET平台。C#语言是一种强类型的,面向对象的语言 ,它具有语法简单、表达力强的特点,而.NET平台则是构成微软的“.NET计划”的基石 。 .NET平台的核心包括两方面,一方面就是著名的通用语言运行机(Common Language Runtime),虽然这个名词起得晦涩了点,不过大家可以拿它和Java的虚拟机来作比较, 二者完成的任务大致相同;另一方面就是一大堆通用函数库,这些库函数可以被多种语 言调用,并且通过编译都产生一种共同的中间语言(Intermediate Language),这种语 言也可以拿Java的字节码来类比,虽然完成的方式有些不一样。 2、C#和Java 下面简单地把C#和Java的相似处列出来,虽然在这里我们重点讨论的是C#和Java的 不同点,但是了解一下二者的相同之处也是很有必要的。 二者都编译成跨平台的、跨语言的代码,并且代码只能在一个受控制的环境中运行 自动回收垃圾内存,并且消除了指针(在C#中可以使用指针,不过必须注明unsafe 关键字) 都不需要头文件,所有的代码都被“包(package)”限制在某个范围内,并且因为没 有头文件,所以消除了类定义的循环依赖 所有的类都是从对象派生出来,并且必须使用New关键字分配内存 用对象加锁的方式来支持多线程 都具有接口(interface)的概念 内部类 继承类的时候不会以某种特定的访问权限来继承; 没有全局函数或者常量,一切必须属于类; 数组或者字符串都自带长度计算和边界检查; 只使用“.”操作符,没有“->”和“::”; “null”、“boolean”和“bool”成为了关键字; 任何变量均在使用前进行初始化; 不能使用整数来返回到if条件语句中,必须使用布尔值; “Try”模块后可以有“finally” ; 3. 属性(Property) 属性的概念对大家来说应该是很熟悉的,类成员函数可以自由地访问本类中的任何 属性成员。不过若要从一个类中去访问另一个类中的属性,那就比较麻烦了,所以很多 时候我们使用Getxxx和Setxxx方法,这样看起来显得极不自然,比如用Java或者C++,代 码是这样的: foo.setSize (getSize () + 1); label.getFont().setBold (true); 但是,在C#中,这样的方法被“属性化”了。同样的代码,在C#就变成了: foo.size++; label.font.bold = true; 可以看出来,C#显然更容易阅读和理解。我们从这个“属性方法”的子程序代码中 ,也可以看到类似情况: Java/C++: public int getSize() { return size; } public void setSize (int value) { size = value; } C#: public int Size { get{return size;} set{size = value;} } 为了区分这种属性化的方法和类的属性成员,在C#中把属性成员称作“域(field)” ,而“属性”则成为这种“属性化的方法”专用的名词。顺便说一句,其实这样的属性 化方法在VB和DELPHI中是经常碰到的,在VB中它也就叫属性。 另外,在C#中Get和Set必须成对出现,一种属性不能只有Get而没有Set(在Java和 C++中就可以只有Get或者只有Set),C#中这样做的好处在于便于维护,假如要对某种属 性进行修改,就会同时注意Get和Set方法,同时修改,不会改了这个忘了那个。 4、对象索引机制(Indexer) C#中引入了对象索引机制。说得明白点,对象索引其实就是对象数组。这里和上一 节中的属性联系起来讲一下,属性需要隐藏Get和Set方法,而在索引机制中,各个对象 的Get或者Set方法是暴露出来的。比如下面的例子就比较清楚地说明了这一点。 public class Skyscraper { Story[] stories; public Story this [int index] { get { return stories [index]; } set { if (value != null) { stories [index] = value; } } } } 5. 指代(Delegate) 指代这个玩意很特别,它有点象指针,但又不完全是,不过大家还是可以把它理解 为一种类型安全的、面向对象的指针。(什么是类型安全和面向对象就不用讲了吧?) 顺便提一句,有很多书上把Delegate翻译成代理,我觉得这样翻不够确切,翻译成“指 代”更恰当些,道理上吻合,并且还符合它的本来意思——微软本来就是用Delegate来 “取代指针”,所以叫“指代”,呵呵。 说起指代,也许至今Sun还会对它愤愤不已,为什么呢?因为在Sun的标准Java中是 没有这个东西的,它是微软99年发布的MSVJ++6添加的“新特性”。为此,两家公司吵得 不亦乐乎,并且还专门在网上写了大量文章互相攻击,有兴趣的朋友可以去看看(只有 英文版)。 http://www.Javasoft.com/docs/white/delegates.html http://msdn.microsoft.com/visualj/technical/articles/delegates/truth.asp 话归正传,指代有什么特点呢?一个明显的特点就是它具有了指针的行为,就好象 从Java又倒回到了C++。在C#中,指代完成的功能大概和C++里面的指针,以及Java中的 接口相当。但是,指代比起C++的“正宗指针”来又要高明一些,因为它可以同时拥有多 个方法,相当于C++里面的指针能同时指向多个函数,并且是类型安全的,这一点体现了 它的“对象”特性;而比起Java的接口来,指代高明的地方在于它能可以不经过内部类 就调用函数,或者用少量代码就能调用多种函数,这一点体现了它的“指针”特性。呵 呵,很有“波粒二象性”的味道吧?指代最重要的应用在于对于事件的处理,下一节我 们将重点介绍。 6、事件(Event) C#对事件是直接支持的(这个特点也是MSVJ所具有的)。当前很多主流程序语言处 理事件的方式各不相同,Delphi采用的是函数指针(这在Delphi中的术语是“closure” )、Java用改编类来实现、VC用WindowsAPI的消息系统,而C#则直接使用delegate和ev ent关键字来解决这个问题。下面让我们来看一个例子,例子中会给大家举出声明、调用 和处理事件的全过程。 //首先是指代的声明,它定义了唤醒某个函数的事件信号 public delegate void ScoreChangeEventHandler (int newScore, ref bool cancel) ; //定义一个产生事件的类 public class Game { // 注意这里使用了event关键字 public event ScoreChangeEventHandler ScoreChange; int score; // Score 属性 public int Score { get { return score; } set { if (score != value) { bool cancel = false; ScoreChange (value, ref cancel); if (! cancel) score = value; } } } // 处理事件的类 public class Referee { public Referee (Game game) { // 裁判负责调整比赛中的分数变化 game.ScoreChange += new ScoreChangeEventHandler (game_ScoreChange); } // 注意这里的函数是怎样和ScoreChangeEventHandler的信号对上号的 private void game_ScoreChange (int newScore, ref bool cancel) { if (newScore < 100) System.Console.WriteLine ("Good Score"); else { cancel = true; System.Console.WriteLine ("No Score can be that high!"); } } } // 主函数类,用于测试上述特性 public class GameTest { public static void Main () { Game game = new Game (); Referee referee = new Referee (game); game.Score = 70; game.Score = 110; } } 在主函数中,我们创建了一个game对象和一个裁判对象,然后我们通过改变比赛分 数,来观察裁判对此会有什么响应。 请注意,我们的这个系统中,Game对象是感觉不到裁判对象的存在的,Game对象在 这里只负责产生事件,至于有谁会来倾听这个事件,并为之作出反应,Game对象是不作 任何表态的。 我们注意到,在裁判类的Referee函数中,Game.ScoreChange后面使用了+=和-=操作 符,这是什么意思呢?回到我们定义ScoreChange的地方,可以发现ScoreChange是用ev ent关键字修饰的,那么这里的意思就很明白了:ScoreChange是一个事件,而事件被触 发后需要相应的事件处理机制,+=/-=就是为这个事件增加/移除相对应的事件处理程序 ,而且,并不是一个事件只能对应一个处理程序,我们还可以用这两个操作符为同一事 件增加/移除数个事件处理程序。怎么样?很方便吧! 在实际应用中,和我们上面讲的(竞赛-裁判)机制很相近的系统就是图形用户界面 系统了。Game对象可以看作是图形界面上的小零件,而得分事件就相当于用户输入事件 ,而裁判就相当于相应的应用程序,用于处理用户输入。 指代机制的首次亮相是在MSVJ里,它是由Anders Hejlsberg发明的,现在又用到了 C#中。指代用在Java语言中的后果,则直接导致了微软和Sun之间对类和指针的关系产生 了大量的争论和探讨。有意思的是,Java的发明者James Gosling非常幽默地称呼指代的 发明者Anders Hejlsberg为“‘函数指针’先生”,因为Anders Hejlsberg总是想方设 法地把指针变相地往各种语言中放;不过有人在看了Java中大量地使用了各种类后,也 戏称Java的发明者James Gosling为“‘全都是类’先生”,真是其中滋味,尽在不言中 啊。
知识点 |
C# |
java |
注释 |
// /* */ ///文档注释 |
// /* */ /** */文档注释 |
main |
Main |
main |
书名 |
书名可以与文件名不同 |
书名与文件名必须相同 |
string |
String string |
String |
输出 |
Console.Write() Console.WriteLine() |
System.out.print 不换行 println |
输入 |
Console.ReadLine() 结果是字符串 |
Scanner input=new Scanner(System.in); int a=input.nextInt() 分类型 |
变量 |
先赋值后使用 不可以重复定义变量 包括局部变量 局部变量作用域相同 |
相同 相同 不包括局部变量 局部变量作用域相同 |
数据类型 |
String string bool 其它的相同 空间大小一样 float a=31.4f; |
String boolean 一样 |
类型转换 |
隐式转换(自动转换)类型相似由小到大 (类型)值 由字符串转其它类型 类型.Parse(必须是字符串); 任意类型之间相互转换 Char a=’0’,int b=a;可以 Int b=48;char a=b;不可以c Char a=48;不可以 |
相同 (类型)值 Char 65—A 97-a 48—0 怒我 就气 死吧 Char a=’0’; Int b=a; 可以 Int b=48; Char a=b//不可以 Char c=48//可以 |
占位符 |
C#有 |
无 |
if |
相同 |
相同 |
Switch() |
语法相同 Case default里面的break不能省 Switch(java出现的都可以,还可以出现字符串) |
语法相同 可以省 Switch只可以判int char 不可以判字符串 |
Scanner |
没有 |
有 |
Arrays |
Array |
Arrays |
Random |
Random rd=new Random() rd.Next(10);//0-9之间的一个整数 rd.Next(1,10);// 1-10之间的一个整数 |
相同 rd.nextInt(10); 无 |
二维数组 |
int[,] a=new int[3,4]; 3层楼每层4间 |
int[][] a=new int[3][4]; |
一维数组 |
Int[] a;//申请一条街 a=new int[5];//在街上盖房子 //逐间住人 a[0]=1;a[1]=2;… //循环查询 For(int i=0;i<a.Length;i++) //a[i]; Int[] a=new int[5];//二合一 Int[] a=new int[]{1,2,3,4,5}; Int[] a= {1,2,3,4,5}; Int a[];//错误 Int[] a=new int[3]{1,2,3};//正确 Int[] a=new int[4]{1,2,3};//错误 |
Int a[]; 正确 Int[] a=new int[3]{1,2,3};//错误 |
变量命名 |
$不可以 |
以字母、下划线、$打头,后面还可以出数字 |
C# |
java |
String string |
String |
求长度 Length 属性 |
length() 方法 |
Equals() |
equals() |
没有 |
equalsIgnoreCase() |
ToUpper() |
toUpperCase() |
ToLower() |
toLowerCase( ) |
+ |
concat() + |
Indexof(char string) |
indexOf(int String ) |
lastIndexOf(char string) |
lastIndexOf( int String) |
String str=”abc123” Str.Substring(2,3);//c12 |
String str=”abc123” Str.substring(2,3);//c |
Trim() 去除首尾空格 |
trim() |
Split(char /char[]) 分开 string[] sp = str.Split('-'); foreach (string a in sp) { Console.WriteLine(a); } |
没有 |
Join(“连接串”,被连接的字符串数组) 连接 str = string.Join(".", sp); Console.WriteLine(str); |
没有 |
其它类型转字符串 其它值.ToString(); Int a |
没有 |
foreach |
|