回 帖 发 新 帖 刷新版面

主题:[原创]java和C#比较学习

2007年11月1日 

  1。访问控制方面:C#有public、internal、protected、private,比java多了个internal,其实它跟java的包访问差不多,internal表示同一个编译集合(如exe、dll)下的类可以互访。 

  对于protected,java和C#有区别。在java中,protected和包访问级别差不多,即不是私有的。而在C#中,protected和private差不多,即它标志的成员是私有的。 

  有这样一种情况:类中的一个成员,需要它能被子类访问到,同时能被同一个集合中(无论是java的包还是C#中的编译集合)的其他类访问到,怎么办呢?在java中,只要用protected就行了。在C#中,可以同时指定internal protected(二者的顺序随意)。 

  在有这样一种情况:类中的一个成员,需要它能被子类访问到,但不能被同一个集合中(无论是java的包还是C#中的编译集合)的其他类访问到,怎么办呢?在C#中,可以指定protected(二者的顺序随意)。但java就无能为力了。 

 2。C#中有static constructor的概念,这跟java中的静态初始模块一样。 

    C# : static [类名]{} 

     java :static{} 

 3。Java中的main函数必须是public static void main(String[] args)的样子,否则虚拟机拒绝运行。C#中,Main函数可以是private的(甚至可以是protected),可以没有参数,可以返回int值。有点像C语言。 

 4。发现csc.exe有一个功能很好,100后面加一个小写的L,它会警告:“l”后缀容易与数字“1”混淆;为清楚起见,请使用“L”。 

 5.C#提供了一种机制,使得某个变量可以被动态赋值一次,以后就不能再改了。那就是readonly关键字的功能。 

 6.java在继承、多态方面,比C#强多了。Java默认的多态,C#要求加上virtual(被继承的方法)和override(继承的方法),而且C#要求不能改变原来的访问修饰符,不像java那样,可以指定更加宽松的访问方式。如果有人利用C#来写程序,必须经常带上virtual和override,还必须照抄原来的访问控制符,不会很郁闷吗?难道有人用C#的面向对象特性时,会舍弃多态的特性?这会引起多大的混乱啊。 

  多态是面向对象的精髓,像java那样默认不是更好吗?  

7. C#中new还可以用来指定子类的某个方法要隐藏父类的具有相同签名的方法。这是不是多余的?你不用也可以,不过csc.exe会警告你,如“lan.Other.Main(string[])”隐藏了继承的成员“lan.HelloWorld.Main(string[])”。如果是有意隐藏,请使用关键字 new。 

像java那样默认多好啊。 

但是话又说回来,C#这样做也是有原因的。如果类B继承了类A,B接下来有添加了一个方法叫做hi(),那是B特有的。然后类A(假设是别人来维护的,你不能看到源码)突然也增加了一个方法hi()。如果B自己那个hi()跟A那个hi()的返回值不一样,当你更新类库A后,可能导致程序运行错误或不能编译。C#就很好就地避免了这种问题。(虽然这种问题出现的概率挺小的…) 

8.C#中,防止一个类被继承,要用关键字sealed。而定义一个常量时,要用const。 

  像java统一用final多好啊。 

9.在C#中,要比较两个引用变量是否指向同一个对象,不能用java中的= =,而要用Object里的ReferenceEquals方法。C#中,不能用一个类的实例去调用该类的类方法,必须用类名。所以java中的o1= =o2等价于C#中的Object.ReferenceEquals(o1,o2)。 

10.C#中没有原始类型的包装类,但是也提供自动装拆箱的功能,和java有的一样。区别是,C#的装箱是自动的,拆箱就要强制转换了。 

int i=100; 

object obj=i; 

i=(int)obj; 

具体怎么装和拆,我们不知道。只知道CLR将int转换成object了。 

11.java的内部类有时候帮助很大。到了C#那,就只提供静态的内部类了。这意味着外部类只相当于是一个命名空间而已。C#中的内部类能访问外部类的私有成员,这可能会让它有点用。 

12.C#中虽然有运算符重载,但是为了整个.net的一致性,应该不会鼓励使用。因为有的.net语言没有运算符重载,而.net的一个目标就是消除各种语言的差别。 

13.C#多了一个struct值类型,它就跟原始类型一样。微软在必要的时候会帮你将struct封装成Object,就像封装int类型一样。以至于你可以认为struct也是由Object继承而来,虽然struct本身并不支持继承。(struct可以不用new来初始化,但它里面的内容必须初始化后才能调用其方法;struct没有析构方法;struct没有默认的构造方法)。 


2007年11月2日 


1.java中类的访问控制符只能是public,或者没有(即默认的包访问)。但是C#中,class和interface的访问控制符可以是public / private / internal / protected / internal protected。当然你必须先取得对类的访问,才可能访问到类的成员。 

 一个C#集合中可以包含多个public的类或接口,跟文件名没有关系。 

2.C#中的接口不能包含常量,而java可以。 

3.C#中的as和java中的instanceof功能一样。但C#提供一个据说是效率更高的as关键字。 

4.接口和抽象类在C#和java中都差不多,这里提一下接口设计和抽象类设计的区别之处。如果你更改了一个接口的设计,比如增加了一个方法,使用你以前的代码的用户将不得不改变他们的代码,否则不能运行和编译。但是如果是一个抽象类,你可以提供一个含默认实现的方法,用户的代码则不需要改变。 

5.C#中一个类实现一个接口时,它的相关方法不必指明override;但一个类继承一个抽象类的抽象方法时,必须加上override,否则视为隐藏。(事实上,只有抽象方法或者是virtual、或者是接口方法才能被覆盖即override。不能无缘无故地override。) 

6。C#中存在一个“多态起始点”的问题。如果一个类实现了接口的某个方法,只是接口到该类才有多态的功能,若要这种多态继承下去,该类必须指明是virtual,多态起始了,接下来的子类提供override就能多态了,不需要更多的virtual。 

  但是抽象类的抽象方法默认就是一个多态起始点,后续的子类只要override就行了。 

7.当一个类实现了两个接口,两个接口有一个相同的方法定义,C#有一种解决机制,叫做显示实现。Java干脆就不处理这种情况,反正实现之后就能调用了,不必指明是哪个接口的,留给程序员自己考虑。 

 当然C#中的显示实现还有其他功能。举个例子,接口A有一个方法叫做f(),类B实现了A。按理说B的实例就能自由调用f()了,但是如果有这样的要求:B的实例只有被cast成A之后才能调用f()。在java中,这样无理的要求是不允许的。但是C#可以做到,就是通过显示实现的方式。有谁会使用这样的特性?(顺便说一下,C#的string类型实现了IConvertible接口,但是你不能直接在一个string调用IConvertible的方法,必须转化为IConvertible之后才行。VS2005中的对象浏览器里也不会显示相关的方法。) 


2007年11月3日 


1.数组,可判断是几维的 foreach 

Java中的多维数组是数组的数组,你可以这样定义一个二维int型数组:int[][] arr=new int[20][],或者定义:int[][] arr =new int[20][20]。 

C#中有两类多维数组,矩形和不平整多维数组。 

 矩形的这样定义:int[,] arr=new int[20,20]; 

 不平整的这样定义:int [][] arr=new int[20][];有人认为不平整的多维数组不就是java的多维数组吗?其实不然,你不能这样定义:int [][] arr=new int[20][20];不平整的就是不能设为“平整”的!同样矩形的就必须是平整的,你不能落下多维数组最后一维的长度。定义三维不平整数组应该类似这样:int [][][] arr=new int[20][][],只有第一维的长度可以指定。然而java却没有这方面的限制。看来C#中的矩形+不平整 多维数组功能还比java的多维数组差。 

C#中的数组不像java中的那么神秘,它们都是System.Array的子类。定义 int [,,] arr=new int[10,10,10] arr的类名是System.int32[,,]; 而int[][][][] arr=new int[20][][][]的类名是System.int32[][][][] 

2.C#和java都支持函数的可变参数。C#引入的params关键字,可以类似这样定义: 

 internal protected int add(params int[] arr)(如果还有其他参数,必须放在params的前面,java中也一样) 

java中类似这样定义: 

static int add(int ... args) 比C#简洁多了。 

(怎么老是引入关键字来支持新语法功能?sealed、const、override、virtual等,java多简洁啊!我想,通过添加关键字,C#的编译器设计起来会更简单,按照关键字来处理代码就行了,不用考虑多种请况。) 

3.看一下数组类型的转换。在java中,你不能将一个String的数组转换成Object数组。而C#支持这种类型的转换。但你不能将一个int的数组转换成object数组。 

4.C#支持索引,这是java中没有的概念。这个概念好像没多大用处。像这样定义: 

public string this[int index]{},类似C#中的属性的概念,大括号里面包含get和set(或二者之一)。 

5.C#和java都支持数组和集合的优化遍历。 

C#中类似这样:foreach(int a in arr)(arr 是一个int数组,注意C#有添加了两个关键字:foreach 和in,这两个关键字就只有这么点用途。) 

Java中可以这样:for(int a : arr),没有添加其他关键字,只有个冒号,简洁多了。 

C#中,要让一个类支持foreach遍历,必须实现IEnumerable接口。看一下IEnumerable的定义: 





namespace System.Collections.Generic 



    // 摘要: 

    //     公开枚举数,该枚举数支持在指定类型的集合上进行简单迭代。 

    public interface IEnumerable<T> : IEnumerable 

    { 

        // 摘要: 

        //     返回一个循环访问集合的枚举数。 

        // 

        // 返回结果: 

        //     可用于循环访问集合的 System.Collections.Generic.IEnumerator<T>。 

        IEnumerator<T> GetEnumerator(); 

    } 



涉及到IEnumerator接口: 

namespace System.Collections.Generic 



    // 摘要: 

    //     支持在泛型集合上进行简单迭代。 

    public interface IEnumerator<T> : IDisposable, IEnumerator 

    { 

        // 摘要: 

        //     获取集合中位于枚举数当前位置的元素。 

        // 

        // 返回结果: 

        //     集合中位于枚举数当前位置的元素。 

        T Current { get; } 

    } 



看到这里,应该知道怎么实现了。就为了支持foreach遍历,就要添加这么多代码,我认为不划算。当然类库里有现成的,拿来用倒无所谓。(顺便提一下,C#的涉及到集合的类多有两个版本,一开始不支持泛型。跟早些出来的java一样啊。) 

Java中要让自己的类支持优化的for遍历,要求类实现lang包里的 

public interface Iterable<E> { 

public java.util.Iterator<E> iterator( ); 



java.util.Iterator接口: 

public interface Iterator<E> { 

public boolean hasNext( ); 

public E next( ); 

public void remove( ); 



6.java和C#泛型比较:二者的实现机制不一样,java通过擦拭的方法实现,C#则有CLR底层的支持,因为还要顾及.net的其他语言。但是增加了一个关键字 where。 

  假设有一个Sorter类。在Java中,Sorter类只接收实现了Comparable的类,可以这样写: 

class Sorter<T implements Comparable>{} 

C#中,假设Sorter只接收实现了IComparable的类,则要这样写: 

  Class Sorter<T> where T:IComparable<T>{} 

7.C#中的string类多了一个Join方法。String.Join (String, String[])第一个参数是分隔符,第二个是需要连接的字符串数组。 


2007年11月4日 


1.C#中的所有之类型都是System.ValueType的子类。 

2.string虽然实现了IClonable(“System成员,支持克隆,即用与现有实例相同的值创建类的新实例。”)接口,但是我觉得string的clone方法什么都没做,只返回一个this引用,何以见得? 

string s3=”x”; 

string s4 = (string)s3.Clone(); 

Console.WriteLine(object.ReferenceEquals(s4, s3));打印true。不过string是immutable的,无所谓了。下面的代码打印false 

string str = "xx"; 

string str1 = string.Copy(str); 

Console.WriteLine(object.ReferenceEquals(str,str1)); 

3.C#中的StringBuilder设计得太差劲了,连基本的方法都没有,没有delete,indexof。 

4.C#逐字字符串

回复列表 (共1个回复)

沙发

加入精华,鼓励一下

我来回复

您尚未登录,请登录后再回复。点此登录或注册