c#语法与c++ 及 java语法的对比分析

早期开发的时候一直用c/c++,后来主要用的是java。最近需要用下c#。

熟悉了下c#,发现c#语言在对c/c++基础上做了很多简化,同时参考了很多java的语法习惯,本来在语法上c/c++就有很多和java类似的地方,现在c#就类似的地方更多了,不过还是有很多区别。

本文总结下c# 和c++及 java的语法差别,重点比较与java的区别,便于相互学习,加强理解。

一、c#与c++的区别

相比c++,c#做了很多简化,使的编写代码更加容易,重要的变化由如下方面:

1、抛弃了指针的使用。在c#中没法使用指针了,在对象成员的调用也只有一种方式,就是通过 . 来引用。

2、完全面向对象。在c#中,不再有全局的函数了。所有的代码都必须在类中。连基本的基本类型都有方法,如:

class Myapp
{
    private static void Main(string[] args)
    {
        int a = 10;
        string value = a.ToString();
        int b = int.Parse(value);
    }
}

3、没有了头文件的概念,类的定义和实现都在类中。

4、引入了命名空间的概念,用于划分源代码,类似java的包的概念。

5、类的继承上废除了多继承的概念,一个类智能有一个父类,而在c++中可以有多个父类。

6、引入了类似java中的接口概念。

7、引入了属性的概念,简化了对成员变量的操作。

 

下面我们重点介绍c# 与java的对比。

 

二、c#与java基本语法的对比

1、程序框架

同java一样,c#要求所有的代码都要在类中,不再同c++一样,既可以定义类,也可以定义全局的方法。

java程序的入口代码必须是某个类中的如下的方法 :

public static void main(String[] args);

而在c#中,入口方法是

static void Main(string[] args)

注意:c#中Main的第一个字母M是大写,且Main方法的参数可以不定义。方法的修饰符也可以不加public。

 

2、包和命名空间

在java中,通过包来组织java源文件。在c#中,通过命名空间来组织c#源文件。 它们的含义和作用是类似的。

区别是,java强制要求java源文件的存放补录必须与包路径严格一致。

在java中,通过import引入包,而在c#中通过using引入命名空间。

两者都可以通过全路径来引用类(这样就不需要import和using了)。

 

3、基本数据类型

两者大部分基本类型的名称都一样,如 int ,char等。枚举定义的关键字都是 enum。数组定义和使用语法也是类似。

典型的区别是:

1)布尔型在java中是 boolean,而在c#中是bool。

2)字符串类型名在java中 是 String ,而在c#中是 string (第一个字母s是小写)。

最关键的是在java中进行字符串内容的比较要用 equlas方法,而在c#中直接可以用 == 比较。

 

4、语句

两者的  if 语句,switch语句,for,while, do ...while,break, continue 使用方式都一致。

有个区别是,在java中,可以用for循环遍历集合。而在c#中需要用单独的关键字 foreach来遍历,但使用方法一样。

 

三、c#与java面向对象语法的对比

java和 c# 都是通过 class关键字来定义类,也都不需要头文件。类的实现代码用  { }扩起。

 1、类的成员

c#中引入了一个属性的概念。

我们知道在java中,为了提高安全性,我们定义成员变量一搬建议定义private的,这样为了其它类能访问该变量,再定义相应的get 和 set 方法,代码如:

class A{
    private int num;
    public void setNum(int num) {
        this.num = num;
    }
    public int getNum() {
        return num;
    }
}

class B{
    public void test(){
        A a = new A();
        a.setNum(10);
        int num = a.getNum();
    }
}

而在c#中,为了简化操作,引入了一个属性的概念,举例如下

class A
{
    public int num { get; set; }
}

class B
{
    public void test()
    {
        A a = new A();
        a.num = 10;
        int re = a.num;
    }
}

在类A中,定义了一个属性 num,在类B中,直接通过属性名可以访问,简化了java中的语法。
在A中定义num时,可以只有get或set标记,表示只读或只写的。

上面的方式存在一个问题,如果在get或set操作时需要通过一定的计算来返回值,既可以采用如下的代码方式。调用方法不变。

class A
{
    private int _num;
    public int num
    {
        get { return _num; }
        set { _num = value*2; }
    }
}

与上面相比,先定义了一个普通的变量_num(这里是private的,不让外部直接访问)。
然后定义了一个属性num,并且有相应的代码,其中set代码中的 value是隐式参数,是在给属性设置值时传入的参数。

这和java代码的使用方式类似了,只是省去了需要定义  setXXX类似的方法。 另外调用时简化了,直接通过属性名就可以。

 

2、访问修饰符

在java中,有 public, protected,private 和 缺省四种级别的修饰符,在定义类和成员时不加修饰符,默认是缺省的。

在c#中,缺省修饰符需要显示的用internal关键字标识,并且如果定义时不加修饰符,默认不是internal 而是 private的。并且在c#中,可以 protected internal组合使用,其含义是访问仅限于该类或当前程序集(同一命名空间)的派生类。单独的protected范围比protected internal大,允许的派生类不限于当前程序集,加上了internal将派生类限制在当前程序集。

 

3、类的继承语法

两者都支持类的继承,在c++中支持多个父类,在c#中进行了简化,同java一样,一个类只允许有一个父类。

在java中通过extends关键字继承类,在c#中采用的是c++的语法,用 :后跟父类表示。两者对父类构造函数的处理机制也不一样。下面举例说明。

下面代码是java的例子:

class A{
    private int num;
    public A(int num){
        this.num = num;
    }
}

class B extends A{
    public B(int num) {
        super(num);
        //其它代码,super语句必须放在第一行。
    }
}

可以看出,在java中使用extends关键字来继承父类,用 super方法来调用父类的构造函数。

下面是c#的代码

class A{
    private int num;
    public A(int num){
        this.num = num;
    }
}

class B : A{
    public B(int num):base(num) {

    }
}

可以看出,在c#中是通过 : 标识符来继承父类,而且是通过base关键字来调用父类构造函数。

4、接口

在java中,引入了接口类型,一个类可以实现一个或多个接口.

在c#中,参考java引入了接口的机制,注意在c++中没有接口的机制。

但两者在实现接口的语法上有些区别,在java中通过implements关键字来标识,而在c#中,使用同继承一样。

下面是java的语法例子

interface hello1{}
interface hello2{}

class A implements hello1,hello2{
    private int num;
    public A(int num){
        this.num = num;
    }
}

class B extends A implements hello1,hello2{
    public B(int num) {
        super(num);
        //其它代码,super语句必须放在第一行。
    }
}

在java中,当一个类同时需要继承父类和实现接口时,extends语句要放在 implements语句前。

下面是c#的语法例子

interface hello1 { }
interface hello2 { }
class A:hello1,hello2{
    private int num;
    public A(int num){
        this.num = num;
    }
}

class B : A,hello1,hello2{
    public B(int num):base(num) {

    }
}

在 c#中,当一个类同时需要继承父类和实现接口时,因为都是跟在 : 后面,需要将父类名放在前面,接口名在后面,如上面例子。

5、重载、重写(多态)

所谓重载,就是一个类可以有多个方法,方法名一样,但参数信息不一样。这个java和 c#都支持。

所谓重写,是面向对象编程中多态特性的体现。就是子类可以定义和父类一样的方法,具体执行时是执行父类方法还是子类方法,动态根据实例绑定。java和c#都有这个特性,区别是使用语法上有些不同。

java的例子:

package com;

public class Demo {
    public static void main(String[] args) {
        A a = new A();
        a.show(); //输出的是 i am A

        B b = new B();
        b.show(); //输出的是 i am B

        A c = new B();
        c.show(); //输出的是 i am B. 多态体现,动态决定调用父类或子类方法。因为c实际是指向B的实例
    }
}

class A {
    public void show() {
        System.out.println("i am A");
    }
}

class B extends A {
    public void show() {
        System.out.println("i am B");
    }
}

可以看出,子类B通过定义相同的方法,重载了父类A的方法。实际执行时,根据变量指向的具体实例决定调用是父类或子类的方法。

c#的例子,c#在多态上的语法参考了c++的特点,需要通过virtual和override关键字来标识。

class Myapp
{
    private static void Main(string[] args)
    {
        A a = new A();
        a.show(); //输出的是 i am A

        B b = new B();
        b.show(); //输出的是 i am B

        A c = new B();
        c.show(); //输出的是 i am B. 多态体现,动态决定调用父类或子类方法。因为c实际是指向B的实例
    }
}

class A {
    virtual public void show() {
        System.Console.WriteLine("i am A");
    }
}

class B : A {
    override public void show() {
        System.Console.WriteLine("i am B");
    }
}

可以看出,在c#中,要想实现继承的多态性,需要在父类方法中用virtual关键字标识,然后在子类的方法中用override关键字进行标识。

需要说明的是,对于父类定义的virtual或非vritual方法,子类可以不重载,但也可以定义同样的方法(没有用override关键字),这是允许的,这时子类的该方法将隐藏父类的方法,这个不是动态的特性。

 

6、抽象类和抽象方法

有时在父类中定义一个序方法,但该方法在基类中不需要有具体的实现,需要在子类中实现。这个特性java和c#都支持。

只是语法上有细微差别。这里举例说明下。

 java的例子:

package com;

public class Demo {
    public static void main(String[] args) {
        B b = new B();
        b.show(); //输出的是 i am B

        A c = new B();
        c.show(); //输出的是 i am B. 多态体现,动态决定调用父类或子类方法。因为c实际是指向B的实例
    }
}

abstract class A {
    public abstract void show();
}

class B extends A {
    public void show() {
        System.out.println("i am B");
    }
}

在java中,是通过abstract关键字标识抽象类和抽象方法的,具体有如下细节:
1)一个类有抽象方法,其所在的类必须定义为抽象类。

2)子类继承抽象父类,要么实现父类的抽象方法,要么继续把自己定义为抽象类。

3)抽象方法没有方法体。抽象类不能实例化。

 下面是c#中的例子

class Myapp
{
    private static void Main(string[] args)
    {
        B b = new B();
        b.show(); //输出的是 i am B

        A c = new B();
        c.show(); //输出的是 i am B. 多态体现,动态决定调用父类或子类方法。因为c实际是指向B的实例
    }
}

abstract class A {
    abstract public void show();
}

class B : A {
     override public void show() {
        System.Console.WriteLine("i am B");
    }
}

除了子类方法定义需要加override关键字,其它语法要求与java一样。另外对抽象类和抽象方法的要求也与java中的要求一致。

 

 四、c#与java其它对比

 1、常量和只读字段

在java中,可以通过final来定义只读变量,可以使成员变量,可以是方法的内的局部变量,也可以是形参。并且定义和初始化可以一起,也可以分开。

如果是定义的的final成员变量,则需要在构造函数中初始化。 如果是方法内的局部变量,可以在定义后赋值。

在c#中,可以用 const关键字定义常量,要求必须在定义时理解赋值。

在c#中,还可以用 readonly来定义类的成员(注意不能定义局部变量),可以在定义时赋值,也可以定义时不赋值,而在构造函数中赋值。

 

2、异常处理

java和 c#有类似的异常处理机制和语法,都有  try, catch, finally, throw 这几个使用关键字。 区别是:

1)java中的异常分为检查时异常和运行期异常两种,而c#中只有一种(运行期异常)。

2)在java中 ,catch语句必须带异常类型参数。

而在c#中,可以不带,表示是缺省的,表示对所有异常处理,但如果定义了多个异常,不带参数的必须放在最后。

 

3、参数传递

在java中,参数传递只有值传递一种方式。对于基本数据类型,如 int等,在方法内无法修改方法的值。

而在c#中,保留了c/c++的特性,通过 ref 和 outer 关键字,可以让形参和实参指向同样的值,这样在方法内修改形参的值,方法外的实参值也跟着变化。

不过,为了提高程序的可读性,建议少用这种特性。

 

4、内部类

在java中,支持内部类,包括匿名内部类。但在c#中,支持内部类,但不支持匿名内部类。

如下面的匿名内部类在java中是允许的,但在c#中是不行的。

package com;

public class Demo {
    public static void main(String[] args) {
        A a = new A() {
            public void show() {
                ;
            }
        };
        a.show();
    }
}

abstract class A {
    public abstract void show();
}

5、分部类

在c#中,编写代码时可以将一个类的定义分到多个cs文件中,后续由编译器自动合并。这个在java中不支持。

这个特性感觉很不好,强烈建议正常情况下不要使用。

 

posted @ 2016-03-28 17:47  51kata  阅读(1990)  评论(0编辑  收藏  举报