C#和java,C#和C++各有什么不同(2) -- 语言规范的比较

15 篇文章 1 订阅
4 篇文章 0 订阅

2.1、简单数据类型
简单数据类型(Primitive)在C#中称为值类型,C#预定义的简单数据类型比Java多。例如,C#有unit,即无符号整数。表2列出了所有C#的预定义数据类型:

表2:C#中的值类型

类型

说明

object

所有类型的最终极的基类

string

字符串类型;字符串是一个Unicode字符的序列

sbyte

8位带符号整数

short

16位带符号整数

int

32位带符号整数

long

64位带符号整数

byte

8位无符号整数

ushort

16位无符号整数

uint

32位无符号整数

ulong

64位无符号整数

float

单精度浮点数类型

double

双精度浮点数类型

bool

布尔类型;bool值或者是true,或者是false

char

字符类型;一个char值即是一个Unicode字符

decimal

有28位有效数字的高精度小数类型


2.2、常量
忘掉Java中的static final修饰符。在C#中,常量可以用const关键词声明。
 

public const int x = 55; 


此外,C#的设计者还增加了readonly关键词。如果编译器编译时未能确定常量值,你可以使用readonly关键词。readonly域只能通过初始化器或类的构造函数设置。

2.3、公用类的入口点
在Java中,公用类的入口点是一个名为main的公用静态方法。main方法的参数是String对象数组,它没有返回值。在C#中,main方法变成了公用静态方法Main(大写的M),Main方法的参数也是一个String对象数组,而且也没有返回值,如下面的原型声明所示:

public static void Main(String[] args) 


但是,C#的Main方法不局限于此。如果不向Main方法传递任何参数,你可以使用上述Main方法的一个重载版本,即不带参数列表的版本。也就是说,下面的Main方法也是一个合法的入口点:

public static void Main() 


另外,如果你认为有必要的话,Main方法还可以返回一个int。例如,下面代码中的Main方法返回1:

using System;
public class Hello
{ 
    public static int Main()
    { 
        Console.WriteLine("Done");
        return 1;
    }
}


与此相对,在Java中重载main方法是不合法的。

2.4、switch语句
在Java中,switch语句只能处理整数。但C#中的switch语句不同,它还能够处理字符变量。请考虑下面用switch语句处理字符串变量的C#代码:

using System;
public class Hello
{
    public static void Main(String[] args)
    {
        switch (args[0])
        {
            case "老板":
                Console.WriteLine("早上好!我们随时准备为您效劳!");
                break;
            case "雇员":
                Console.WriteLine("早上好!你可以开始工作了!");
                break;
            default:
                Console.WriteLine("早上好!祝你好运!");
                break;
        }
    }
}


与Java中的switch不同,C#的switch语句要求每一个case块或者在块的末尾提供一个break语句,或者用goto转到switch内的其他case标签。

2.5、foreach语句
foreach语句枚举集合中的各个元素,为集合中的每一个元素执行一次代码块。请参见下面的例子。

using System;
public class Hello
{
    public static void Main(String[] args)
    {
        foreach (String arg in args)
        {
            Console.WriteLine(arg);
        }
    }
}


如果在运行这个执行文件的时候指定了参数,比如“Hello Peter Kevin Richard”,则程序的输出将是下面几行文字:

Hello
Peter
Kevin
Richard

2.6、C#没有>>>移位操作符
C#支持uint和ulong之类的无符号变量类型。因此,在C#中,右移操作符(即“>>”)对于无符号变量类型和带符号变量类型(比如int和long)的处理方式不同。右移uint和ulong丢弃低位并把空出的高位设置为零;但对于int和long类型的变量,“>>”操作符丢弃低位,同时,只有当变量值是正数时,“>>”才把空出的高位设置成零;如果“>>”操作的是一个负数,空出的高位被设置成为1。

Java中不存在无符号的变量类型。因此,我们用“>>>”操作符在右移时引入负号位;否则,使用“>>”操作符。

2.7、goto关键词
Java不用goto关键词。在C#中,goto允许你转到指定的标签。不过,C#以特别谨慎的态度对待goto,比如它不允许goto转入到语句块的内部。在Java中,你可以用带标签的语句加上break或continue取代C#中的goto。

2.8、声明数组
在Java中,数组的声明方法非常灵活,实际上有许多种声明方法都属于合法的方法。例如,下面的几行代码是等价的:

int[] x = { 0, 1, 2, 3 };
int x[] = { 0, 1, 2, 3 }; 


但在C#中,只有第一行代码合法,[]不能放到变量名字之后。

2.9、包
在C#中,包(Package)被称为名称空间。把名称空间引入C#程序的关键词是“using”。例如,“using System;”这个语句引入了System名称空间。

然而,与Java不同的是,C#允许为名称空间或者名称空间中的类指定别名:

using TheConsole = System.Console;
public class Hello
{
    public static void Main()
    {
        TheConsole.WriteLine("使用别名");
    }
}


虽然从概念上看,Java的包类似于.NET的名称空间。然而,两者的实现方式不同。在Java中,包的名字同时也是实际存在的实体,它决定了放置.java文件的目录结构。在C#中,每一个源代码文件可以从属于多个名称空间,而且它可以容纳多个公共类。

.NET中包的实体称为程序集(Assembly)。每一个程序集包含一个manifest结构。manifest列举程序集所包含的文件,控制哪些类型和资源被显露到程序集之外,并把对这些类型和资源的引用映射到包含这些类型与资源的文件。程序集是自包含的,一个程序集可以放置到单一的文件之内,也可以分割成多个文件。.NET的这种封装机制解决了DLL文件所面临的问题,即臭名昭著的DLL Hell问题。

2.10、默认包
在Java中,java.lang包是默认的包,它无需显式导入就已经自动包含。例如,要把一些文本输出到控制台,你可以使用下面的代码:

System.out.println("Hello world from Java");


C#中不存在默认的包。如果要向控制台输出文本,你使用System名称空间Console对象的WriteLine方法。但是,你必须显式导入所有的类。代码如下:

using System;
public class Hello
{
    public static void Main()
    {
        Console.WriteLine("Hello world from C#");
    }
}


2.11、面向对象
Java和C#都是完全面向对象的语言。在面向对象编程的三大原则方面,这两种语言接近得不能再接近。


继承:这两种语言都支持类的单一继承,但类可以实现多个接口。所有类都从一个公共的基类继承。
封装与可见性:无论是在Java还是C#中,你都可以决定类成员是否可见。除了C#的internal访问修饰符之外,两者的可见性机制非常相似。
多态性:Java和C#都支持某些形式的多态性机制,且两者实现方法非常类似。
2.12、可访问性
类的每个成员都有特定类型的可访问性。C#中的访问修饰符与Java中的基本对应,但多出了一个internal。简而言之,C#有5种类型的可访问性,如下所示:
 

public成员可以从任何代码访问
protected成员只能从派生类访问
internal成员只能从同一程序集的内部访问
protected internal成员只能从同一程序集内的派生类访问
private成员只能在当前类的内部访问


2.13、派生类
在Java中,我们用关键词“extends”实现继承。C#采用了C++的类派生语法。例如,下面的代码显示了如何派生父类Control从而创建出新类Button:

public class Button: Control { . . } 


2.14、最终类
由于C#中不存在final关键词,如果想要某个类不再被派生,你可以使用sealed关键词,如下例所示:

sealed class FinalClass { . . } 


2.15、接口
接口这个概念在C#和Java中非常相似。接口的关键词是interface,一个接口可以扩展一个或者多个其他接口。按照惯例,接口的名字以大写字母“I”开头。下面的代码是C#接口的一个例子,它与Java中的接口完全一样:

interface IShape { void Draw(); } 


扩展接口的语法与扩展类的语法一样。例如,下例的IRectangularShape接口扩展IShape接口(即,从IShape接口派生出IRectangularShape接口)。

interface IRectangularShape: IShape { int GetWidth(); } 


如果你从两个或者两个以上的接口派生,父接口的名字列表用逗号分隔,如下面的代码所示:

interface INewInterface: IParent1, IParent2 { } 


然而,与Java不同,C#中的接口不能包含域(Field)。

另外还要注意,在C#中,接口内的所有方法默认都是公用方法。在Java中,方法声明可以带有public修饰符(即使这并非必要),但在C#中,显式为接口的方法指定public修饰符是非法的。例如,下面的C#接口将产生一个编译错误。

interface IShape { public void Draw(); } 


2.16、is和as操作符
C#中的is操作符与Java中的instanceof操作符一样,两者都可以用来测试某个对象的实例是否属于特定的类型。在Java中没有与C#中的as操作符等价的操作符。as操作符与is操作符非常相似,但它更富有“进取心”:如果类型正确的话,as操作符会尝试把被测试的对象引用转换成目标类型;否则,它把变量引用设置成null。

为正确理解as操作符,首先请考虑下面这个例子中is操作符的运用。这个例子包含一个IShape接口,以及两个实现了IShape接口的类Rectangle和Circle。

using System;

interface IShape
{
    void draw();
}

public class Rectangle : IShape
{
    public void draw()
    {
    }
    public int GetWidth()
    {
        return 6;
    }
}

public class Circle : IShape
{
    public void draw()
    {
    }
    public int GetRadius()
    {
        return 5;
    }
}

public class LetsDraw
{
    public static void Main(String[] args)
    {
        IShape shape = null;
        if (args[0] == "rectangle")
        {
            shape = new Rectangle();
        }
        else if (args[0] == "circle")
        {
            shape = new Circle();
        }
        if (shape is Rectangle)
        {
            Rectangle rectangle = (Rectangle)shape;
            Console.WriteLine("Width : " + rectangle.GetWidth());
        }
        if (shape is Circle)
        {
            Circle circle = (Circle)shape;
            Console.WriteLine("Radius : " + circle.GetRadius());
        }
    }
}


编译好代码之后,用户可以输入“rectangle”或者“circle”作为Main方法的参数。如果用户输入的是“circle”,则shape被实例化成为一个Circle类型的对象;反之,如果用户输入的是“rectangle”,则shape被实例化成为Rectangle类型的对象。随后,程序用is操作符测试shape的变量类型:如果shape是一个矩形,则shape被转换成为Rectangle对象,我们调用它的GetWidth方法;如果shape是一个圆,则shape被转换成为一个Circle对象,我们调用它的GetRadius方法。

如果使用as操作符,则上述代码可以改成如下形式:

using System;

interface IShape
{
    void draw();
}

public class Rectangle : IShape
{
    public void draw()
    {
    }
    public int GetWidth()
    {
        return 6;
    }
}

public class Circle : IShape
{
    public void draw()
    {
    }
    public int GetRadius()
    {
        return 5;
    }
}

public class LetsDraw
{
    public static void Main(String[] args)
    {
        IShape shape = null;
        if (args[0] == "rectangle")
        {
            shape = new Rectangle();
        }
        else if (args[0] == "circle")
        {
            shape = new Circle();
        }

        Rectangle rectangle = shape as Rectangle;
        if (rectangle != null)
        {
            Console.WriteLine("Width : " + rectangle.GetWidth());
        }
        else
        {
            Circle circle = shape as Circle;
            if (circle != null)
            {
                Console.WriteLine("Radius : " + circle.GetRadius());
            }
        }
    }
}


在上面代码的粗体部分中,我们在没有测试shape对象类型的情况下,就用as操作符把shape转换成Rectangle类型的对象。如果shape正好是一个Rectangle,则shape被转换成为Rectangle类型的对象并保存到rectangle变量,然后我们调用它的GetWidth方法。如果这种转换失败,则我们进行第二次尝试。这一次,shape被转换成为Circle类型的对象并保存到circle变量。如果shape确实是一个Circle对象,则circle现在引用了一个Circle对象,我们调用它的GetRadius方法。

2.17、库
C#没有自己的类库。但是,C#共享了.NET的类库。当然,.NET类库也可以用于其他.NET语言,比如VB.NET或者JScript.NET。值得一提的是StringBuilder类,它是对String类的补充。StringBuilder类与Java的StringBuffer类非常相似。

2.18、垃圾收集
C++已经让我们认识到手工管理内存是多么缺乏效率和浪费时间。当你在C++中创建了一个对象,你就必须手工地拆除这个对象。代码越复杂,这个任务也越困难。Java用垃圾收集器来解决这个问题,由垃圾收集器搜集不再使用的对象并释放内存。C#同样采用了这种方法。应该说,如果你也在开发一种新的OOP语言,追随这条道路是一种非常自然的选择。C#仍旧保留了C++的内存手工管理方法,它适合在速度极端重要的场合使用,而在Java中这是不允许的。

2.19、异常处理
如果你听说C#使用与Java相似的异常处理机制,你不会为此而惊讶,对吧?在C#中,所有的异常都从一个名为Exception的类派生(听起来很熟悉?)另外,正如在Java中一样,你还有熟悉的try和catch语句。Exception类属于.NET System名称空间的一部分。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值