|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
ruby里有这些工具吗?又要简单多少?我没有用过这两门语言,我估计在这些语言力没有很统一的这种标准,或者根本就没有提供。编程本文会商Java和C#之间的异同点,目标在于当迁徙到.NET时,让Java开辟职员把握所触及的一些常识。Java和C#之间的次要类似点是:
•Java和C#都源于C++,而且共有C++的一些特性。
•两种言语都必要编译成两头代码,而不是间接编译成纯呆板码。Java编译成Java假造机(JavaVirtualMachine,JVM)字节码,而C#则编译成大众两头言语(CommonIntermediateLanguage,CIL)。
•Java字节码是经由过程称为Java假造机(JVM)的使用程序实行的。相似地,已编译的C#程序由大众言语运转库(CommonLanguageRuntime,CLR)实行。
•除一些渺小的不同之外,C#中的非常处置与Java十分类似。C#用try...catch机关来处置运转时毛病(也称为非常),这和Java中是完整一样的。System.Exception类是一切C#非常类的基类。
•同Java一样,C#是强范例反省编程言语。编译器可以检测在运转时大概会呈现成绩的范例毛病。
•同Java一样,C#供应主动渣滓接纳功效,从而使编程职员制止了跟踪分派的资本。
•Java和C#都撑持单一承继和多接话柄现。
如今让我们看一看本文涵盖的主要差别:
•C#言语引进了一些新的言语机关,如foreach、索引器、属性、托付、运算符重载和其他言语机关。在本文前面我们将更具体地会商这些机关。
本页内容
源文件商定
顶层声明
完整限制名和定名空间别号
预处置指令
言语语法
转换和强迫转换
值范例和援用范例
装箱(Boxing)和拆箱(Unboxing)
运算符
流程把持
类基本
Main()办法
其他办法
利用不断定数量的参数
属性
布局
C#中的数组
承继和派生类
将范例强迫转换到基类
选择机关函数
办法重写
笼统类
接口
运算符重载
非常
初级C#手艺
渣滓接纳
平安代码和不平安代码
小结
源文件商定
我们必要晓得,两种言语在源程序的文件定名商定和布局上有一些分歧:
文件定名
包括C#类的文件的定名商定与Java有点分歧。起首,在Java中,一切源文件的扩大名都为.java。每一个源文件都包括一个顶层大众类声明,而且类名必需与文件名相婚配。换句话说,一个用大众局限声明的名为Customer的类必需界说在具着名称Customer.java的源文件中。
而C#源代码是由.cs扩大名暗示的。与Java分歧,源文件能够包括多个顶层大众类声明,而文件名不必要与任何类名相婚配。
前往页首
顶层声明
在Java和C#中,源代码以按必定按次分列的顶层声明入手下手。Java和C#程序中的声明只存在少量不同。
Java中的顶层声明
在Java中,我们能够用package关头字将类组合在一同。打包的类必需在源文件的第一个可实行的行中利用package关头字。接着呈现的是必要会见其他包中的类的任何导进语句,以后是类声明,好比:
package;
import.;
classCustomer
{
...
}
C#中的顶层声明
C#利用定名空间的观点,经由过程namespace关头字将逻辑上相干的类组合在一同。这些做法相似于Java包,而具有不异称号的类能够呈现在两个分歧的定名空间中。要会见界说在以后定名空间以外的定名空间中的类,我们可使用紧跟该定名空间名的using关头字,以下所示:
using.;
namespace
{
classCustomer
{
...
}
}
注重,using语句能够完整正当地放在定名空间声明中,在这类情形下,如许导进的定名空间就构成了包括定名空间的一部分。
Java不同意在不异的源文件中有多个包,而C#同意在一个.cs文件中有多个定名空间:
namespaceAcmeAccounting
{
publicclassGetDetails
{
...
}
}
namespaceAcmeFinance
{
publicclassShowDetails
{
...
}
}
前往页首
完整限制名和定名空间别号
同Java一样,经由过程供应类的完整限制名(如System.Data.DataSet或下面的示例中的AcmeAccounting.GetDetails),我们能够在没有定名空间的using援用的情形下会见.NET或用户界说的定名空间中的类。
完整限制名大概会变得很长而方便于利用,在这类情形下,我们可使用using关头字来指定一个简称或别号,以进步代码的可读性。
鄙人面的代码中,创立了一一般名来援用由一个假造的公司所编写的代码:
usingDataTier=Acme.SQLCode.Client;
usingSystem;
publicclassOutputSales
{
publicstaticvoidMain()
{
intsales=DataTier.GetSales("January");
Console.WriteLine("JanuarysSales:{0}",sales);
}
}
注重WriteLine()的语法,格局字符串中带有{x},个中x暗示在此处要拔出的值的参数列表的地位。假定GetSales()办法前往500,则该使用程序的输入将为:
JanuarysSales:500
前往页首
预处置指令
与C和C++类似,C#包含预处置器指令,预处置器指令供应了有前提地跳过源文件的某些部分、呈报毛病和告诫前提,和形貌源代码的分歧部分的才能。利用“预处置指令”这个术语只是为了与C和C++编程言语坚持分歧,由于C#其实不包含独自的预处置步骤。有关C#预处置器指令的完全列表,请拜见C#预处置器指令。
前往页首
言语语法
在这一部分中,我们会商这两种言语之间的类似点和分歧点。一些次要的分歧点有:
•常量声明―Java为此而利用final关头字,而C#利用关头字const或readonly。
•复合数据范例―在Java中,我们可使用类关头字来创立作为没无方法的类的复合数据范例,可是C#为此供应了struct,同C中一样。
•析构函数―C#同意我们创立在烧毁类的实例之前挪用的析构函数办法。在Java中,能够供应finalize()办法来包括在将对象作为渣滓接纳之前扫除资本的代码。在C#中,由类析构函数来供应此功效。析构函数相似一个没有参数并后面带有波形符“~”的机关函数。
•函数指针―C#供应一个称为delegate的机关来创立范例平安的函数指针。Java没有任何与之对等的机制。
数据范例
C#供应了在Java中可用的一切数据范例,而且增添了对无标记数和新的128位高精度浮点范例的撑持。
在Java中,关于每一个基础数据范例,中心类库都供应了一个包装类来将其暗示为Java对象。比方,Integer类包装int数据范例,而Double类包装double数据范例。
而在C#中,一切的基础数据范例都是System定名空间中的对象。关于每一个数据范例,都供应一个简称或别号。比方,int是System.Int32的简称,而double是System.Double的简写情势。
上面的列表给出了C#数据范例及其别号。能够看到,前8个对应于Java中可用的基础范例。不外,请注重,Java的boolean在C#中称为bool。
C#数据范例
简称.NET类范例宽度局限(位)
byte
System.Byte
无标记整数
8
-128到127
sbyte
System.SByte
有标记整数
8
-128到127
int
System.Int32
有标记整数
32
-2,147,483,648到2,147,483,647
uint
System.UInt32
无标记整数
32
0到4294967295
short
System.Int16
有标记整数
16
-32,768到32,767
ushort
System.UInt16
无标记整数
16
0到65535
long
System.Int64
有标记整数
64
-922337203685477508到922337203685477507
ulong
System.UInt64
无标记整数
64
0到18446744073709551615
float
System.Single
单精度浮点范例
32
-3.402823e38到3.402823e38
double
System.Double
双精度浮点范例
64
-1.79769313486232e308到1.79769313486232e308
char
System.Char
单个Unicode字符
16
用在文本中的Unicode标记
bool
System.Boolean
逻辑Boolean范例
8
true或false
object
System.Object
一切其他范例的基础范例
string
System.String
字符序列
decimal
System.Decimal
能够暗示具有29个无效位的小数的准确分数或整数范例
128
-2x10-96到2x1096
由于C#将一切的基础数据范例都暗示为对象,以是依照基础数据范例来挪用对象办法是大概的。比方:
inti=10;
Console.WriteLine(i.ToString());
借助于主动装箱和拆箱,能够到达此目标。更多信息请拜见装箱和拆箱。
列举
与C/C++类似,在C#中可使用列举来组合已定名常量,而在Java中不克不及利用列举。上面的示例界说了一个复杂的Color列举。
publicenumColor{Green,Orange,Red,Blue}
还能够为列举赋整数值,以下面的列举声明所示:
publicenumColor{Green=10,Orange=20,Red=30,Blue=40}
上面的程序挪用Enum范例的GetNames办法来显现列举的可用常量。然后,它将值赋给列举,并显现该值。
usingSystem;
publicclassTypeTest
{
publicstaticvoidMain()
{
Console.WriteLine("Possiblecolorchoices:");
//Enum.GetNamesreturnsastringarrayofnamedconstantsfortheenum
foreach(stringsinEnum.GetNames(typeof(Color)))
{
Console.WriteLine(s);
}
ColorFavoriteColor=Color.Blue;
Console.WriteLine("FavoriteColoris{0}",FavoriteColor);
Console.WriteLine("FavoriteColorvalueis{0}",(int)FavoriteColor);
}
}
在运转以后,该程序将显现以下了局:
Possiblecolorchoices:
Green
Orange
Red
Blue
FavoriteColorisBlue
FavoriteColorvalueis40
字符串
在Java和C#中,字符串范例体现出类似的举动,只要一些渺小的不同。两者的字符串范例均是不成改动的,这意味着一旦字符串创立终了,就不克不及改动字符串的值。在两者的实例中,看起来像修正字符串实践内容的办法实践上创立一个新的字符串供前往,而保存原始的字符串稳定。在C#和Java中,对照字符串值的历程是分歧的。在Java中,为了对照字符串的值,开辟职员必要依照字符串范例挪用equals()办法,正如在默许情形下==运算符对照援用范例一样。在C#中,开辟职员可使用==或!=运算符来间接对照字符串的值。在C#中,只管字符串是援用范例,可是在默许情形下,==和!=运算符将对照字符串的值而不是援用。在本文前面,我们将会商值范例和援用。
正如在Java中一样,C#开辟职员不该该利用字符串范例来毗连字符串,以免每次毗连字符串时都创立新的字符串类的开支。相反,开辟职员可使用System.Text定名空间中的StringBuilder类,它在功效上同等于Java中的StringBuffer类。
字符串
C#供应了制止在字符串常量中利用本义序列(如代表制表符的“ ”或代表反斜杠字符的“”)的功效。要如许做,能够在为字符串赋值之前利用@标记来声明字符串。上面的示例显现了怎样利用本义字符和怎样为字符串赋值:
//Usingescapedcharacters
stringpath="\FileShareDirectoryfile.txt";
//UsingStringLiterals
stringescapedPath=@"FileShareDirectoryfile.txt";
前往页首
转换和强迫转换
Java和C#恪守类似的数据范例主动转换和强迫转换划定规矩。
同Java一样,C#既撑持隐式范例转换又撑持显式范例转换。在扩展转换的情形下,转换是隐式的。比方,上面从int到long的转换是隐式的,好像Java中的一样:
intintVariable=5;
longl=intVariable;
上面是.NET数据范例之间的隐式转换列表:
隐式转换
源范例方针范例
byte
short,ushort,int,uint,long,ulong,float,double或decimal
sbyte
short,int,long,float,double,?decimal
int
long,float,double,或decimal
uint
long,ulong,float,double,或decimal
short
int,long,float,double,或decimal
ushort
int,uint,long,ulong,float,double,或decimal
long
float,double,或decimal
ulong
float,double,或decimal
float
double
char
ushort,int,uint,long,ulong,float,double,或decimal
可使用与Java一样的语法对但愿显式转换的表达式举行强迫转换:
longlongVariable=5483;
intintVariable=(int)longVariable;
显式转换
源范例方针范例
byte
sbyte或char
sbyte
byte,ushort,uint,ulong,或char
int
sbyte,byte,short,ushort,uint,ulong,或char
uint
sbyte,byte,short,ushort,int,或char
short
sbyte,byte,ushort,uint,ulong,或char
ushort
sbyte,byte,short,或char
long
sbyte,byte,short,ushort,int,uint,ulong,或char
ulong
sbyte,byte,short,ushort,int,uint,long,或char
float
sbyte,byte,short,ushort,int,uint,long,ulong,char,或decimal
double
sbyte,byte,short,ushort,int,uint,long,ulong,char,float,或decimal
char
sbyte,byte,或short
decimal
sbyte,byte,short,ushort,int,uint,long,ulong,char,float,或double
前往页首
值范例和援用范例
C#撑持两种变量范例:
•值范例―这些是内置的基础数据范例,比方char、int、float和用struct声明的用户界说范例。
•援用范例―从基础范例机关而来的类和其他庞大数据范例。这类范例的变量其实不包括范例的实例,而只是包括对实例的援用。
让我们稍微深切地研讨一下这个成绩。假如我们创立两个值范例变量i和j,好比:
inti=10;
intj=20;
:值范例的内存地位
则i和j相互完整自力,而且分派了分歧的内存地位:
假如我们改动这些变量中的某一个的值,另外一个天然不会遭到影响。比方,假如我们有一个如许的表达式:
intk=i;
则变量之间仍旧没有接洽。也就是说,以后假如我们改动i的值,k还会保存赋值时i具有的值。
但是,援用范例的做法却分歧。比方,我们能够如许声明两个变量:
myClassa=newmyClass();
myClassb=a;
如今,由于类是C#中的援用范例,以是a称为对myClass的援用。下面两行中的第一行在内存中创立了myClass的一个实例,而且将a设置为援用该实例。因而,当我们将b设置为即是a时,它就包括了对内存中类的援用的反复。假如我们如今改动b中的属性,a中的属性就将反应这些改动,由于这二者都指向内存中的不异对象,以下图所示:
:援用范例的内存地位
前往页首
装箱(Boxing)和拆箱(Unboxing)
这类将值范例转换为援用范例的历程称为装箱。而相反的将援用范例转换为值范例的历程就称为拆箱。以下面的代码所示:
intvalueVariable=10;
//boxing
objectobj=refVariable;
//unboxing
intvalueVariable=(int)refVariable;
Java必要我们手动实行如许的转换。经由过程机关如许的对象,能够将基础数据范例转换成包装类的对象(装箱)。一样,经由过程挪用这类对象中的得当办法,也能够从包装类的对象中提取基础数据范例的值(拆箱)。有关装箱的更多信息,请拜见装箱转换;有关拆箱的更多信息,请拜见拆箱转换。
前往页首
运算符
C#供应了Java撑持的一切可用运算符,以下表所示。在表的开端,您将看到一些新的运算符,它们能够在C#中利用而不成以在Java中利用:
运算符
种别标记
[Text]
[Text]
一元
++--+-!~()
乘法
*/%
加法
+-
移位
<>
干系
<=>=instanceof
相称
==!=
逻辑与
&
逻辑异或
^
逻辑或
|
前提与
&&
前提或
||
前提
?:
赋值
=*=/=%=+=-=<<=>>=&=^=|=
操纵数的范例
typeof
操纵数的巨细
sizeof
实行溢出反省
checked
作废溢出反省
unchecked
独一不成以在C#中利用的Java运算符是>>>移位运算符。之以是在Java中存在此运算符,是由于该言语中缺少无标记变量,比方在必要右移位以在最高无效比特位拔出1时。
但是,C#撑持无标记变量,因此C#只必要尺度>>运算符。取决于操纵数是不是带有标记,此运算符发生分歧的了局。右移一个无标记数会在最高无效比特位拔出0,而右移一个有标记数则会复制后面的最高无效比特位。
checked和unchecked运算符
假如关于分派给正在利用的数据范例的比特数来讲了局太年夜,则算术运算会发生溢出。关于特定的整数算术运算,经由过程利用checked和unchecked关头字,能够反省或疏忽如许的溢出。假如表达式是一个利用checked的常量表达式,则会在编译时发生毛病。
上面这个复杂的示例申明了这两个运算符的用法
usingSystem;
publicclassClass1
{
publicstaticvoidMain(string[]args)
{
shorta=10000,b=10000;
shortd=unchecked((short)(10000*10000));
Console.WriteLine(d=+d);
shortc=(short)(a*b);
Console.WriteLine(c=+c);
shorte=checked((short)(a*b));
Console.WriteLine(e=+e);
}
}
在这段代码中,unchecked运算符制止了产生编译时毛病,不然,上面的语句会发生毛病:
shortd=unchecked((short)(10000*10000));
下一个表达式在默许情形下是不反省的,因而值会悄然溢出:
shortc=(short)(a*b);
我们可使用checked运算符来强迫反省该表达式是不是会在运转时溢出:
shorte=checked((short)(a*b));
当运转时,赋第一个值给d&c会以值-7936悄然溢出,可是当试图利用checked()以取得e的乘积值时,程序会激发System.OverflowException非常。
注重:别的,经由过程利用命令行编译器开关(/checked)大概间接在VisualStudio中基于每一个项目利用此开关,您还能够把持是不是反省代码块中的算术溢出。
is运算符
此运算符断定右边对象的范例是不是与右侧指定的范例相婚配:
if(objReferenceisSomeClass)...
鄙人面的示例中,CheckType()办法打印一条动静,形貌传送给它的参数的范例:
usingSystem;
publicclassShowTypes
{
publicstaticvoidMain(string[]args)
{
CheckType(5);
CheckType(10f);
CheckType("Hello");
}
privatestaticvoidCheckType(objectobj)
{
if(objisint)
{
Console.WriteLine("Integerparameter");
}
elseif(objisfloat)
{
Console.WriteLine("Floatparameter");
}
elseif(objisstring)
{
Console.WriteLine("Stringparameter");
}
}
}
运转此程序,输入以下:
Integerparameter
Floatparameter
Stringparameter
sizeof运算符
sizeof运算符以指定值范例的字节数前往其巨细,以下面的代码所示:
usingSystem;
publicclassSize
{
publicstaticvoidMain()
{
unsafe
{
Console.WriteLine("Thesizeofshortis{0}.",sizeof(short));
Console.WriteLine("Thesizeofintis{0}.",sizeof(int));
Console.WriteLine("Thesizeofdoubleis{0}.",sizeof(double));
}
}
}
注重,包括sizeof运算符的代码放在一个不平安的块中。这是由于sizeof运算符被以为是一个不平安的运算符(因为它间接会见内存)。有关不平安代码的更多信息,请拜见平安代码和不平安代码。
typeof和GetType
typeof运算符前往作为System.Type对象传送给它的类的范例。GetType()办法是相干的,而且前往类或非常的运转时范例。typeof和GetType()都能够与反射一同利用,以静态地查找关于对象的信息,以下面的示例所示:
usingSystem;
usingSystem.Reflection;
publicclassCustomer
{
stringname;
publicstringName
{
set
{
name=value;
}
get
{
returnname;
}
}
}
publicclassTypeTest
{
publicstaticvoidMain()
{
TypetypeObj=typeof(Customer);
Console.WriteLine("TheClassnameis{0}",
typeObj.FullName);
//OrusetheGetType()method:
//Customerobj=newCustomer();
//TypetypeObj=obj.GetType();
Console.WriteLine("
TheClassMembers
=================
");
MemberInfo[]class_members=typeObj.GetMembers();
foreach(MemberInfomembersinclass_members)
{
Console.WriteLine(members.ToString());
}
Console.WriteLine("
TheClassMethods
=================
");
MethodInfo[]class_methods=typeObj.GetMethods();
foreach(MethodInfomethodsinclass_methods)
{
Console.WriteLine(methods.ToString());
}
}
}
运转此程序,输入以下:
TheClassnameisCustomer
TheClassMembers
=================
Int32GetHashCode()
BooleanEquals(System.Object)
System.StringToString()
Voidset_Name(System.String)
System.Stringget_Name()
System.TypeGetType()
Void.ctor()
System.StringName
TheClassMethods
=================
Int32GetHashCode()
BooleanEquals(System.Object)
System.StringToString()
Voidset_Name(System.String)
System.Stringget_Name()
System.TypeGetType()
这为我们显现了从System.Object承继的一切类的成员,而且还展现了一种办法,C#在外部将get和set属性accessors暗示为get_xxx()和set_xxx()办法。
鄙人一个示例中,我们利用GetType()在运转时查找表达式的范例:
usingSystem;
publicclassTypeTest
{
publicstaticvoidMain()
{
intradius=8;
Console.WriteLine("Calculatedareais={0}",
radius*radius*System.Math.PI);
Console.WriteLine("Theresultisoftype{0}",
(radius*radius*System.Math.PI).GetType());
}
}
此程序的输入告知我们,了局是System.Double范例,选择它是由于System.Math.PI是这类范例。
Calculatedareais=201.061929829747
TheresultisoftypeSystem.Double
前往页首
流程把持
在这两种言语中,流程把持语句长短常类似的,可是这一部分也会会商它们的一些渺小不同。
分支语句
分支语句依据特定的前提改动运转时程序实行的流程。
if、else和elseif
这些在两种言语中是一样的。
switch语句
在两种言语中,switch语句都供应前提多分支操纵。可是有点分歧的是,Java同意您“超出”一个case并实行下一个case,除非您在case的开端利用了break语句。但是,C#必要在每一个case的开端都利用break或goto语句,假如二者都不存在,则编译器会发生以下毛病:
Controlcannotfallthroughfromonecaselabeltoanother.
不外请注重,在没有指定要实行的代码的中央,当case婚配时,把持会超出随后的case。当在switch语句中利用goto时,我们只能跳至统一switch中的另外一个case块。假如我们想要跳至defaultcase,我们可使用“gotodefault;”,不然,我们必要利用“gotocasecond;”,个中cond是我们但愿跳至的case的婚配前提。Java的switch语句的另外一个分歧的地方在于,在Java中,我们只能对整数范例利用switch语句,而C#同意我们对字符串变量利用switch语句。
比方,上面的程序在C#中是正当的,但在Java中倒是分歧法的:
switch(args[0])
{
case"copy":
...
break;
case"move":
...
gotocase"delete";
break;
case"del":
case"remove":
case"delete":
...
break;
default:
...
break;
}
goto的前往
在Java中,goto是一个没有完成的保存关头字。但是,我们可使用带有break或continue标签的语句来到达与goto类似的目标。
C#同意goto语句跳至带有标签的语句。不外请注重,为了跳至一个特定的标签,goto语句必需在该标签的局限内。换句话说,goto不成用来跳进一个语句块(不外,它能够跳出一个语句块)、跳出一个类,或加入try...catch语句中的finally块。不外请注重,在年夜多半情形下,我们都不勉励您利用goto,由于它违背了面向对象编程的优秀理论。
轮回语句
轮回语句反复指定的代码块,直到满意给定的前提为止。
for轮回
在两种言语中,for轮回的语法和操纵均不异:
for(initialization;condition;expression)
statement;
foreach轮回
C#引进了一种新的轮回范例,称为foreach轮回(相似于VisualBasic的ForEach)。foreach轮回同意遍历撑持IEnumerable接口的容器类中的每项(比方:数组)。上面的代码申明了怎样利用foreach语句来输入一个数组的内容:
publicstaticvoidMain()
{
int[]arr1=newint[]{1,2,3,4,5,6};
foreach(intiinarr1)
{
Console.WriteLine("Valueis{0}",i);
}
}
在C#中的数组部分,我们将更具体地先容C#中的数组。
while和do...while轮回
在两种言语中,while和do...while语句的语法和操纵均不异:
while(condition)
{
//statements
}
Asusual,dontforgetthetrailing;indo...whileloops:
do
{
//statements
}
while(condition);
前往页首
类基本
会见润色符
C#中的润色符与Java大抵不异,我们将在这一部分先容个中的一些渺小不同。每一个类成员或类自己都能够用会见润色符举行声明,以界说允许会见的局限。没有在其他类中声明的类只能指定public或internal润色符,而嵌套的类(如其他的类成员)能够指定上面五个润色符中的任何一个:
•public―对一切类可见
•protected―仅从派生类中可见
•private―仅在给定的类中可见
•internal―仅在不异的程序会合可见
•protectedinternal―仅对以后的程序集或从包括类中派生的范例可见
public、protected和private润色符
public润色符使得能够从类表里的任何中央会见成员。protected润色符暗示会见仅限于包括类或从它派生的类。private润色符意味着只大概从包括范例中举行会见。
internal润色符
internal项只能够在以后的程序会合举行会见。.NET中的程序集大抵同等于Java的JAR文件,它暗示能够从中机关其他程序的天生块。
protectedinternal润色符
protectedinternal项仅对以后程序集或从包括类派生的范例可见。在C#中,默许会见润色符是private,而Java的默许会见润色符是包局限。
sealed润色符
在其类声明中带有sealed润色符的类能够以为是与笼统类完整相反的类―它不克不及被承继。我们能够将一个类标志为sealed,以避免其他类重写它的功效。天然地,sealed类不克不及是笼统的。同时还必要注重,该布局是隐式密封的;因而,它们不克不及被承继。sealed润色符相称于在Java顶用final关头字标志类。
readonly润色符
要在C#中界说常量,我们可使用const或readonly润色符交换Java的final关头字。在C#中,这两个润色符之间的区分在于,const项是在编译时处置的,而readonly字段是在运转时设置的。这能够同意我们修正用于在运转时断定readonly字段值的表达式。
这意味着给readonly字段的赋值能够呈现在类机关函数及声明中。比方,上面的类声了然一个名为IntegerVariable的readonly变量,它是在类机关函数中初始化的:
usingSystem;
publicclassReadOnlyClass
{
privatereadonlyintIntegerConstant;
publicReadOnlyClass()
{
IntegerConstant=5;
}
//Wegetacompiletimeerrorifwetrytosetthevalueofthereadonly
//classvariableoutsideoftheconstructor
publicintIntMember
{
set
{
IntegerConstant=value;
}
get
{
returnIntegerConstant;
}
}
publicstaticvoidMain(string[]args)
{
ReadOnlyClassobj=newReadOnlyClass();
//Wecannotperformthisoperationonareadonlyfield
obj.IntMember=100;
Console.WriteLine("ValueofIntegerConstantfieldis{0}",
obj.IntMember);
}
}
注重,假如readonly润色符使用于静态字段,它就应当在该静态字段中举行初始化。
类的机关函数。
前往页首
Main()办法
每一个C#使用程序都必需http://msdn.microsoft.com/vstudio/java/gettingstarted/csharpforjava/#ArraysinC#只能包括一个Main()办法,Main()办法指定程序从那边入手下手实行。注重,在C#中,Main()用年夜写字母开首,而Java利用小写的main()。
Main()只能前往int或void,而且有一个可选的字符串数组参数来暗示命令行参数:
staticintMain(string[]args)
{
...
return0;
}
字符串数组参数能够包括任何传进的命令行参数,这与Java中完整一样。因而,args[0]指定第一个命令行参数,而args[1]暗示第二个参数,等等。与C++分歧的是,args数组不包括EXE文件的称号。
前往页首
其他办法
当将参数传送给办法时,它们大概经由过程值传送,也大概经由过程援用传送。值参数只提取任何变量的值以在办法中利用,因此挪用代码中的变量值不受办法中对这些参数所实行的操纵的影响。
而援用型参数指向在挪用代码中声明的变量,因此在经由过程援用传送时,办法将修正该变量的内容。
经由过程援用传送
在Java和C#中,援用对象的办法参数老是经由过程援用传送,而基础数据范例参数则经由过程值传送。
在C#中,一切参数在默许情形下都是经由过程值传送的。要经由过程援用举行传送,我们必要指定关头字ref或out中的一个。这两个关头字的分歧的地方在于参数的初始化。ref参数必需在利用行进行初始化,而out参数无需在传送行进行显式初始化,而且任何先前的值城市被疏忽。
请注重,当办法将援用范例作为参数利用时,援用自己是经由过程值传送的。但是,援用仍旧指向内存中的统一对象,因而对对象的属性所做的任何改动在办法加入以后将坚持稳定。可是,由于援用自己是经由过程值传送的,以是在办法内它应当改成指向一个分歧的对象乃至一个新对象,而一旦办法实行终了,援用就会恢复为指向本来的对象,即便本来的对象是未赋值的也一样云云。
ref关头字
当我们但愿挪用的办法永世性地改动用作参数的变量的值时,我们能够在参数中指定此关头字。产生传送的不是在挪用中利用的变量值,而是对变量自己的援用。然后,办法感化于援用,如许,在办法实行过程当中对参数所做的变动就保留到用作办法的参数的原始变量中。
上面的代码用Add()办法对此举行了申明,个中,第二个int参数是利用ref关头字经由过程援用传送的:
usingSystem;
publicclassRefClass
{
publicstaticvoidMain(string[]args)
{
inttotal=20;
Console.WriteLine("Originalvalueoftotal:{0}",total);
//CalltheAddmethod
Add(10,reftotal);
Console.WriteLine("ValueafterAdd()call:{0}",total);
}
publicstaticvoidAdd(inti,refintresult)
{
result+=i;
}
}
这个复杂示例的输入了局标明,对result参数所做的改动反应在Add()挪用所用的变量total中:
Originalvalueoftotal:20
ValueafterAdd()call:30
这是由于result参数援用了挪用代码中的total变量所占用的实践内存地位。请注重,类的属性不是一个变量,而且不克不及间接用作ref范例的参数。
注重,在挪用办法时,ref关头字必需在参数之前,在办法声明中一样云云。
out关头字
out关头字的感化与ref关头字十分类似,而且对利用out关头字声明的参数所做的修正在办法外是可见的。它与ref有两点分歧:起首,out参数的任何初始值在办法中都是疏忽的;其次,out参数必需在办法中赋值:
usingSystem;
publicclassOutClass
{
publicstaticvoidMain(string[]args)
{
inttotal=20;
Console.WriteLine("Originalvalueoftotal:{0}",total);
Add(33,77,outtotal);
Console.WriteLine("ValueafterAdd()call:{0}",total);
}
publicstaticvoidAdd(inti,intj,outintresult)
{
//Thefollowinglinewouldcauseacompileerror
//Console.WriteLine("Initialvalueinsidemethod:{0}",result);
result=i+j;
}
}
在该示例中,Add()办法的第三个参数是用out关头字声明的,而且对该办法的挪用还必要将out关头字用于该参数。输入了局为:
Originalvalueoftotal:20ValueafterAdd()call:110
因而,总的来讲,当您但愿办法修正现有的变量时,可使用ref关头字,而利用out关头字来前往在该办法中发生的值。当办法为挪用代码发生多个了局值时,一般一同利用out关头字与该办法的前往值。
前往页首
利用不断定数量的参数
经由过程在声明办法时指定params关头字,C#同意我们发送可变数量的参数。参数列表也能够包括一般参数,可是必要注重,用params关头字声明的参数必需放在最初。它接纳可变长度数组的情势,而且每一个办法只要一个params参数。
当编译器实验剖析一个办法挪用时,它查找其参数列表与挪用的办法相婚配的办法。假如找不到能够与参数列表婚配的办法重载,可是存在与得当范例的params参数婚配的版本,则会挪用该办法,并将分外的参数放在一个数组中。
上面的示例对此举行了演示:
usingSystem;
publicclassParamsClass
{
publicstaticvoidMain(string[]args)
{
Average("ListOne",5,10,15);
Average("ListTwo",5,10,15,20,25,30);
}
publicstaticvoidAverage(stringtitle,paramsint[]values)
{
intSum=0;
Console.Write("Averageof{0}:",title);
for(inti=0;i<values.Length;i++)
{
Sum+=values[i];
Console.Write(values[i]+",");
}
Console.WriteLine(":{0}",(float)Sum/values.Length);
}
}
在下面的示例中,用整型数组中的params参数声了然办法Average,让我们利用任何数量的参数来挪用它。输入了局以下:
AverageofListOne:5,10,15,:10
AverageofListTwo:5,10,15,20,25,30,:17.5
注重,假如我们但愿同意分歧范例的不断定参数,我们能够指定Object范例的params参数。
前往页首
属性
在C#中,属性是类、struct,或接口的定名成员,它供应了一种简便的路子,能够经由过程所谓的get和set会见器办法会见公有字段。
上面的代码片段为类Animal声了然一个名为Species的属性,它笼统了对名为name的公有变量的笼统会见:
publicclassAnimal
{
privatestringname;
publicstringSpecies
{
get
{
returnname;
}
set
{
name=value;
}
}
}
一般,属性与它会见的外部成员有不异的称号,可是属性以年夜写字母开首(比方下面的示例中的Name),大概外部成员带有“_”前缀。同时还必要注重set会见器中所用的名为value的隐式参数―这类参数具有基本成员变量范例。
实践上,会见器在外部暗示成get_X()和set_X()办法,从而与.NET言语坚持兼容,由于.NET言语其实不撑持会见器(如本文后面的typeOf和GetType()部分中的屏幕截图所示)。一旦界说好属性,就能够十分简单地猎取或设置它的值:
Animalanimal=newAnimal()
//Settheproperty
animal.Species="Lion";
//Getthepropertyvalue
stringstr=animal.Species;
假如属性只要get会见器,它就是一个只读属性。假如它只要set会见器,它就是一个只写属性。假如二者都有,则它是一个可读写属性。
前往页首
布局
C#撑持struct关头字,它是源于C的另外一个项,可是不成用于Java。能够将struct看做是一个轻量级类。它能够接纳与类大抵不异的体例包括机关函数、常量、字段、办法、属性、索引器、运算符和嵌套范例。structs分歧于类,由于它们不克不及是笼统的,而且不撑持完成承继。布局与类另有一点主要的分歧,布局是值范例的,而类是援用范例的。在机关函数的事情体例上,布局也有所分歧。出格是,编译器老是供应默许的不带参数的机关函数,而且不同意您交换它。
鄙人面的示例中,我们利用new关头字而且经由过程初始化实例的成员初始化了一个struct:
usingSystem;
publicstructCustomerStruct
{
publicintID;
publicstringname;
publicCustomerStruct(intcustomerID,stringcustomerName)
{
ID=customerID;
name=customerName;
}
}
classTestClass
{
publicstaticvoidMain(string[]args)
{
//DeclareaCustomerStructusingthedefaultconstructor
CustomerStructcustomer=newCustomerStruct();
Console.WriteLine("Structvaluesbeforeinitialization");
Console.WriteLine("ID={0},Name={1}",customer.ID,
customer.name);
customer.ID=100;
customer.name="Robert";
Console.WriteLine("Structvaluesafterinitialization");
Console.WriteLine("ID={0},Name={1}",customer.ID,
customer.name);
}
}
当我们编译并运转下面的代码时,它的输入显现,该布局的变量在默许情形下是已初始化的。int变量初始化为0,而字符串变量初始化为空字符串:
初始化前的struct变量
ID=0,Name=
初始化后的truct值
ID=100,Name=Robert
注重,当我们利用另外一种暗示法(CustomerStructcustomer)声明customer时,它的成员变量将不被初始化,因而,假如试图在为它们赋值前利用它们,将会发生编译时毛病。
前往页首
C#中的数组
数组是具有不异数据范例的项的有序汇合,经由过程数组名和所希冀的项相对数组入手下手地位的偏移量能够会见数组。与Java比拟,在C#中声明和利用数组的体例有一些主要的分歧,我将在这一部分中对此举行先容。
一维数组
一维数组以线性体例存储了流动数量的项,它仅仅必要一个索引值就能够断定任何一项。
在C#中,数组声明中的方括号必需紧跟数据范例,而不成以像在Java中一样呈现在变量名的前面。因而,可使用上面的语法来声明整数范例的数组:
int[]MyArray;
而上面的声明在C#中是有效的:
intMyArray[];
一旦声了然数组,就能够利用新的关头字来设置它的巨细,这与Java中是完整一样的:
int[]MyArray;//declaresthearrayreference
MyArray=newint[5];//createsa5elementintegerarray
然后,我们就能够利用与Java完整不异的语法来会见一维数组中的元素,注重C#数组的索引也是从零入手下手的:
MyArray[4]//accessesthelastelementinthearray
初始化
可使用与Java不异的语法在创立时对数组元素举行初始化:
MyArray=newint[5]{1,2,3,4,5};
与Java分歧,初始化器的数量必需与数组巨细完整婚配。我们能够使用这一特征在一行中声明和初始化C#数组:
int[]TaxRates={0,20,23,40,50};
此语法创立了一个巨细与初始化器的数量相称的数组。
程序轮回中的初始化
C#中初始化数组的另外一种办法就是利用foreach轮回。上面的轮回将数组中的每一个元素都设置为零:
int[]MyLittleArray=newint[5];
foreach(intiinMyLittleArray)
{
MyLittleArray[i]=0;
}
交织数组
C#和Java都撑持创立交织大概说非矩形的数组,个中的每行都包括分歧数量的列。比方,上面的交织数组的第一行有四项,而第二行有三项:
int[][]JaggedArray=newint[2][];
JaggedArray[0]=newint[4];
JaggedArray[1]=newint[3];
多维数组
C#同意我们创立划定规矩的多维数组,它能够看做是不异范例的值的矩阵。固然Java和C#都撑持交织的数组,可是C#还撑持多维数组或数组的数组。我们将即刻先容交织数组。
利用上面的语法,我们能够声明一个多维矩形数组:
int[,]My2DIntArray;
float[,,,]My4DFloatArray;
个中,My2DintArray是能够借此会见每一个元素的称号。
注重,int[][]My2DintArray;行在C#中有分歧的寄义,我们很快就会分明这一点。
一旦声了然数组,我们就能够如许给它分派内存:
int[,]My2DIntArray;//declaresarrayreference
My2DIntArray=newint[5,4];//allocatesspacefor5x4integers
然后,可使用上面的语法来会见数组的元素:
My2DIntArray[4,3]=906;
由于数组是从零入手下手的,以是这将第四行第五列中的元素(右下角)设置为906。
初始化
经由过程上面的任何一种办法,都能够在一行中创立、设置和初始化多维数组:
int[,]intArray={{1,2,3},
{4,5,6}};
int[,]intArray=newint[2,3]{{1,2,3},
{4,5,6}};
int[,]intArray=newint[,]{{1,2,3},
{4,5,6}};
程序轮回中的初始化
数组中一切的元素都可使用嵌套的轮回举行初始化,以下所示:
int[,]intArray=newint[5,4];
foreach(intiinintArray)
{
foreach(intjinintArray[])
{
j=0;
}
}
System.Array类
在.NET中,数组是作为System.Array类的实例完成的。此类供应了几个有效的办法,比方Sort()和Reverse()。
上面的程序申明了利用这几个办法是何等的简单。起首,我们利用Array类的Reverse()办法来使数组的元素反向,然后,我们利用Sort()办法对它们举行排序:
usingSystem;
publicclassArrayMethods
{
publicstaticvoidMain()
{
//Createstringarrayofsize5
string[]EmployeeNames=newstring[5];
Console.WriteLine("Enterfiveemployeenames:");
//Read5employeenamesfromuser
for(inti=0;i<5;i++)
{
EmployeeNames[i]=Console.ReadLine();
}
//Printthearrayinoriginalorder
Console.WriteLine("
**OriginalArray**");
foreach(stringEmployeeNameinEmployeeNames)
{
Console.Write("{0}",EmployeeName);
}
//printthearrayinreverseorder.
Console.WriteLine("
**ValuesinReverseOrder**");
System.Array.Reverse(EmployeeNames);
foreach(stringEmployeeNameinEmployeeNames)
{
Console.Write("{0}",EmployeeName);
}
//printthearrayinsortedorder.
Console.WriteLine("
**ValuesinSortedOrder**");
System.Array.Sort(EmployeeNames);
foreach(stringEmployeeNameinEmployeeNames)
{
Console.Write("{0}",EmployeeName);
}
}
}
上面是此程序的一些典范输入:
Enterfiveemployeenames:
Luca
Angie
Brian
Kent
Beatriz
**OriginalArray**
LucaAngieBrianKentBeatriz
**ValuesinReverseOrder**
BeatrizKentBrianAngieLuca
**ValuesinSortedOrder**
AngieBeatrizBrianKentLuca
前往页首
承继和派生类
经由过程创立一个从现有类派生的新类,我们能够扩大现有类的功效。派生类承继了基类的属性,而且我们能够在必要时增加或重写办法和属性。
在C#中,承继和接话柄现都经由过程:运算符来界说,这同等于Java中的扩大和完成。注重,基类应当一向在类声明的最右边。
同Java一样,C#不撑持多重承继,这意味着类不克不及从多个类中承继。但是,我们能够为此目标而接纳与Java不异的体例利用接口,正如我们鄙人一部分中将看到的。
上面的代码界说了一个名为Point的类,它有两个公有成员变量x和y,暗示点的地位。这些变量能够分离经由过程名为X和Y的属性来会见:
publicclassPoint
{
privateintx,y;
publicPoint()
{
x=0;
y=0;
}
publicintX
{
get
{
returnx;
}
set
{
x=value;
}
}
publicintY
{
get
{
returny;
}
set
{
y=value;
}
}
}
我们将从Point类派生一个新类(好比说名为ColorPoint),以下所示:
publicclassColorPoint:Point
因而ColorPoint承继了基类的一切字段和办法,我们能够依据必要向派生类中增加新的字段和办法来供应分外的特征。在这个示例中,我们增加了一个公有成员和一些会见器来为点增添色彩:
usingSystem.Drawing;
publicclassColorPoint:Point
{
privateColorscreenColor;
publicColorPoint()
{
screenColor=Color.Red;
}
publicColorScreenColor
{
get
{
returnscreenColor;
}
set
{
screenColor=value;
}
}
}
注重,派生类的机关函数隐式挪用了基类(或Java术语中的超类)的机关函数。在承继中,一切的基类机关函数都是依照这些类呈现在类条理中的按次在派生类的机关函数之前挪用的。
前往页首
将范例强迫转换到基类
与在Java中一样,我们不克不及利用对基类的援用来会见派生类的成员和办法,即便基类援用大概包括对派生范例对象的无效援用也一样云云。
我们能够经由过程隐式地援用派生的范例来援用派生类:
ColorPointclrpt=newColorPoint();
Pointpt=clrpt;
在这段代码中,基类援用pt包括clrpt援用的正本。
base关头字
经由过程利用base关头字,我们能够会见子类中的基类成员,即便这些基类成员在超类中被重写也一样云云。比方,我们能够创立一个派生类,该类所包括的办法具有与基类中不异的署名。假如我们在此办法前加上new关头字,就暗示这是一个属于派生类的全新办法。经由过程base关头字,我们仍旧能够供应办法来会见基类中的原始办法。
比方,我们的Point基类着名为invert()的办法,它互换x和y坐标。经由过程利用上面如许的代码,我们能够在派生类ColorPoint中供应此办法的替换办法:
publicnewvoidinvert()
{
intholding=X;
X=Y;
Y=holding;
screenColor=Color.Gray;
}
正如您所见,该办法互换x和y,然后将点的色彩设置为灰色。经由过程在ColorPoint中创立另外一个办法(比方上面的这个办法),我们能够供应对此办法的基完成的会见:
publicvoidbaseInvert()
{
base.invert();
}
然后,我们就能够经由过程挪用baseInvert()办法来挪用ColorPoint对象中的基办法。
ColorPointclrpt=newColorPoint();clrpt.baseInvert();
请记着,假如我们将对基类的援用赋值给ColorPoint的实例,然后会见它的办法,我们将取得不异的效果:
Pointpt=clrpt;
pt.invert();
前往页首
选择机关函数
基类对象老是在任何派生类之前机关的。因而基类的机关函数在派生类的机关函数之前实行。假如基类有多个机关函数,派生类就能够决意要挪用的机关函数。比方,我们能够修正我们的Point类来增加第二个机关函数:
publicclassPoint
{
privateintx,y;
publicPoint()
{
x=0;y=0;
}
publicPoint(intx,inty)
{
this.x=x;
this.y=y;
}
}
然后,经由过程利用base关头字,我们能够将ColorPoint类变动为利用某个特定的可用机关函数:
publicclassColorPoint:Point
{
privateColorcolor;
publicColorPoint(intx,inty):base(x,y)
{
color=Color.Red;
}
}
在Java中,这项功效是经由过程super关头字来完成的。
前往页首
办法重写
经由过程为声明的办法供应新的完成,派生类能够重写基类的办法。Java和C#之间的一个主要区分在于,Java办法在默许情形下标志为虚办法,而在C#中,必需利用virtual润色符才干将办法显式标志为虚办法。能够接纳大抵不异的体例重写属性会见器和办法。
虚办法
派生类中要被重写的办法是用virtual润色符声明的。而在派生类中,已被重写的办法用override润色符声明。
override润色符暗示派生类的办法或属性,这个派生类取代基类中具有不异的称号和署名的类。要被重写的基办法必需声明为virtual、abstract或override:以这类体例重写非虚办法或静态办法是不成能的―请拜见关于此成绩的下一部分。已被重写的办法或属性和重写办法或属性必需具有不异的会见级润色符。
上面的示例显现了一个称为StepUp的虚办法,它是在派生类顶用override润色符重写的:
usingSystem;
publicclassCountClass
{
publicintcount;
//Constructor
publicCountClass(intstartValue)
{
count=startValue;
}
publicvirtualintStepUp()
{
return++count;
}
}
classCount100Class:CountClass
{
//Constructor
publicCount100Class(intx):base(x)
{
}
publicoverrideintStepUp()
{
return((base.count)+100);
}
publicstaticvoidMain()
{
CountClasscounter=newCountClass(10);
CountClassbigCounter=newCount100Class(10);
Console.WriteLine("Valueofcountinbaseclass={0}",
counter.StepUp());
Console.WriteLine("Valueofcountinderivedclass={0}",
bigCounter.StepUp());
}
}
当我们运转这段代码时,会发明派生类的机关函数利用基类中给出的办法体,这使得我们在不复制该代码的情形下就能够初始化count成员。上面是我们失掉的输入了局:
Valueofcountinbaseclass=11
Valueofcountinderivedclass=110
前往页首
笼统类
笼统类将一个(或多个)办法或属性声明为笼统的。如许的办法其实不具有声明它们的类中供应的完成,只管笼统类也能够包括非笼统办法,也就是说,已为其办法供应了完成。笼统类不克不及间接实例化,而只能作为派生类。如许的派生类必需为一切的笼统办法和属性供应完成(利用override关头字),除非派天生员自己被声明为笼统的。
上面的示例声了然一个笼统的Employee类。我们还创立了一个名为Manager的派生类,它供应了界说在Employee类中的笼统办法show()的完成:
usingSystem;
publicabstractclassEmployee
{
//abstractshowmethod
publicabstractvoidshow();
}
//ManagerclassextendsEmployee
publicclassManager:Employee
{
stringname;
publicManager(stringname)
{
this.name=name;
}
//overridetheshowmethod
publicoverridevoidshow()
{
Console.WriteLine("Name:"+name);
}
}
publicclassCreateManager
{
publicstaticvoidMain(string[]args)
{
//CreateinstanceofManagerandassignittoanEmployeereference
Employeetemp=newManager("JohnChapman");
//Callshowmethod.ThiswillcalltheshowmethodoftheManagerclass
temp.show();
}
}
这段代码挪用了由Manager类供应的show()完成,而且在屏幕上打印出雇员的名字。
前往页首
接口
接口是一种“骨干类”,包括办法署名可是没无方法的完成。在这个方面,接口与笼统类一样,只包括笼统办法。C#接口十分相似于Java接口,事情道理基础一样。
接口的一切成员都界说为大众成员,而且接口不克不及包括常量、字段(公有数据成员)、机关函数、析构函数或任何范例的静态成员。假如为接口的成员指定任何润色符,编译器将会发生毛病。
为了完成接口,我们能够从接口派生类。如许的派生类必需为一切接口的办法供应完成,除非派生类声明为笼统的。
接口的声明与Java完整一样。在接口界说中,经由过程独自利用get和set关头字,属性仅唆使它的范例,和它是只读的、只写的仍是可读写的。上面的接口声了然一个只读属性:
publicinterfaceIMethodInterface
{
//methodsignatures
voidMethodA();
intMethodB(floatparameter1,boolparameter2);
//properties
intReadOnlyProperty
{
get;
}
}
用一个冒号来取代Java的完成关头字,类就能够承继此接口。完成类必需供应一切办法的界说和任何须需的属性会见器:
publicclassInterfaceImplementation:IMethodInterface
{
//fields
privateintcount=0;
privateintID;
//implementmethodsdefinedininterface
publicvoidMethodA()
{
...
}
publicintMethodB(floatparameter1,boolparameter2)
{
...
returnintegerVariable;
}
publicintReadOnlyProperty
{
get
{
returncount;
}
}
//addextramethodsifrequired
}
完成多个接口
经由过程利用上面的语法,一个类能够完成多个接口:
publicclassMyClass:interfacename1,interfacename2,interfacename3
假如一个类完成多个接口,则成员的称号会存在二义性,经由过程利用属性或办法名的完整限制符能够办理这个成绩。换句话说,经由过程利用办法的完整限制名来唆使它属于哪一个接口(比方属于IMethodInterface.MethodA),派生类能够办理这类抵触。
前往页首
运算符重载
与C++一样,C#同意我们重载运算符,以供在我们本人的类中利用。这大概使得用户界说的数据范例看起来很天然,而且能够在逻辑上作为基础数据范例利用。比方,我们能够创立一个新的名为Complex的数据范例来暗示一个庞大的数字,而且供应一些办法,以利用尺度的算术运算符对如许的数字举行算术运算,比方利用+运算符来使两个庞大的数字相加。
为了重载一个运算符,我们编写了一个函数,它将必要重载的运算符的标记放在称号operator的前面。比方,我们能够如许来重载+运算符:
publicstaticcomplexoperator+(complexlhs,complexrhs)
一切的运算符重载都是类的静态办法。同时也必要注重,假如您重载即是运算符(==),您还必需重载不即是运算符(!=)。
能够重载的运算符的完全列表以下:
•一元运算符:+,-,!,~,++,--,true,false
•二元运算符:+,-,*,/,%,&,|,^,<<,>>,==,!=,>,<,>=,<=
下一个示例创立了一个Complex类,该类重载+和-运算符:
usingSystem;
publicclasscomplex
{
privatefloatreal;
privatefloatimg;
publiccomplex(floatp,floatq)
{
real=p;
img=q;
}
publiccomplex()
{
real=0;
img=0;
}
publicvoidPrint()
{
Console.WriteLine("{0}+{1}i",real,img);
}
//Overloading+operator
publicstaticcomplexoperator+(complexlhs,complexrhs)
{
complexsum=newcomplex();
sum.real=lhs.real+rhs.real;
sum.img=lhs.img+rhs.img;
return(sum);
}
//Overloading-operator
publicstaticcomplexoperator-(complexlhs,complexrhs)
{
complexresult=newcomplex();
result.real=lhs.real-rhs.real;
result.img=lhs.img-rhs.img;
return(result);
}
}
此类同意我们利用代码来创立和操纵两个庞大的数字,以下所示:
usingSystem;
publicclassComplexClass
{
publicstaticvoidMain(string[]args)
{
//Setupcomplexnumbers
complexA=newcomplex(10.5f,12.5f);
complexB=newcomplex(8.0f,4.5f);
complexC;
//PrintobjectAandB
Console.Write("ComplexNumberA:");
A.Print();
Console.Write("ComplexNumberB:");
B.Print();
//AddAandB,printresult
C=A+B;
Console.Write("
A+B=");
C.Print();
//SubtractAandB,printresult
C=A-B;
Console.Write("A-B=");
C.Print();
}
}
正如程序所演示的,我们如今能够很直不雅地对属于庞大类的对象利用加减运算符。上面是我们失掉的输入:
ComplexNumberA:10.5+12.5i
ComplexNumberB:8+4.5i
A+B=18.5+17i
A-B=2.5+8i
固然Java在外部为字符串联接重载了+运算符,可是它其实不撑持运算符重载。
前往页首
非常
C#中的非常处置与Java十分类似。
在程序实行的过程当中,不管甚么时分呈现了严峻毛病,.NET运转库城市创立一个Exception对象来处置该毛病。在.NET中,Exception是一切非常类的基类。从Exception基类派生了两品种其余非常:System.SystemException和System.ApplicationException。System定名空间中的一切范例都是从System.SystemException派生的,而用户界说的非常应当从System.ApplicationException派生,以便辨别运转库毛病和使用程序毛病。一些罕见的System非常包含:
•IndexOutOfRangeException―利用了年夜于数组或汇合巨细的索引
•NullReferenceException―在将援用设置为无效的实例之前利用了援用的属性或办法
•ArithmeticException―在操纵发生溢出或下溢时激发的非常
•FormatException―参数或操纵数的格局不准确
与Java中一样,当我们有简单引发非常的代码时,我们应当将此代码放在try块中。紧接厥后的是一个或多个供应毛病处置的catch块,而且我们还能够对任何我们想实行但又不晓得是不是激发非常的代码利用finally块。
注重:当利用多个catch块时,捕捉非常的代码必需以升序的按次安排,如许就只要第一个与激发的非常相婚配的catch块会被实行。C#编译器会强迫如许做,而Java编译器不会如许做。
C#也与Java一样,catch块其实不必要参数;在短少参数的情形下,catch块合用于任何Exception类。
比方,当从文件中举行读取时,大概会碰到FileNotFoundException或IOException,起首,我们必要安排更详细的FileNotFoundException处置程序:
try
{
//Codetoopenandreadafile
}
catch(FileNotFoundExceptionfe)
{
//Handlefilenotfoundexceptionfirst
}
catch(IOExceptionioe)
{
//NowhandleanyotherIOexceptions
}
catch
{
//Thisblockwillcatchallotherexceptions
}
finally
{
//Executedwhetherornotanexceptionoccurs,oftentoreleaseresources
}
经由过程从Exception派生,我们能够创立我们本人的非常类。比方,上面的代码创立了一个InvalidDepartmentException类,例如说,当某个部门的一个新雇员纪录为有效时,我们大概激发该类。用户界说的非常的类机关函数利用base关头字来挪用基类机关函数,并发送一个得当的动静:
publicclass
Java的桌面程序开发在java程序员里通常叫swing开发,主要用的swing包里的类开发的,也就是通常说的c/s架构开发 |
|