C#基础学习

1 程序结构

1.1 C#的组成部分

  • 命名空间声明;
  • 一个类(class);
  • 类方法;
  • 类属性;
  • 一个 main 方法;
  • 语句和表达式;
  • 注释。

1.2 C# 程序结构

下面我们通过一个命名行窗口打印“Hello World” 的示例程序,来具体演示一下 C# 程序的组成,代码如下:

// using 关键字用来在程序中引入 System 命名空间,一个程序中可以有多个using语句。
using System;

// namespace 关键字用来声明一个命名空间,c.biancheng.net则是命名空间的名字。命名空间是类的集合,上面代码中名为“c.biancheng.net”的命名空间中包含了一个名为“Program”的类。
namespace c.biancheng.net
{
    // class 关键字用来定义一个类,“Program” 则是类的名字,类中通常用来存放程序中要使用的数据和函数(也叫方法)。
    class Program
    {
    //  main为定义的函数名称,main 函数是整个 C# 程序的入口,其中包含了程序运行时需要执行的操作。static 和 void 都是用来修饰 main 函数的关键字。 
        static void  main(string[] args)
        {
            // 此代码用来在命令行窗口中输出“Hello World!”。WriteLine 是 system 命名空间中定义的 Console 类里面的方法,用来输出一些信息。
            Console.WriteLine("Hello World!");
            // 此行代码是针对 VS.NET 用户的,它会是程序进入等待状态,敲击键盘上的任意一个按键即可让程序继续运行。之所以需要这些代码,是因为命令行窗口会在程序运行结束后自动关闭,这会导致我们想要输出的内容一闪而过,加入此代码则可以避免这种情况。
            Console.ReadKey();
        }
    }
}

运行结果:

  • 打开VS Code,编辑完程序之后保存;
  • 将文件名命名为xx.cs格式;
  • 使用快捷键 Ctrl+ ` 调出终端;
  • 使用 csc xx.cs 将其编译成 xx.exe文件
  • 执行 run xx.exe 运行

C# 的注意事项

  • 一个程序中可以有多个 using 语句;
  • Main() 函数是整个 C# 程序的入口
  • C# 区分大小写;
  • 所有语句和表达式都必须以英文的分号 ; 结尾;
  • 程序从 main 函数开始执行;
  • 与 Java 不同,程序文件名可以与类名不同;
  • 代码中出现 {} 都是成对出现的,用来标记代码块,{} 中包裹的代码可以看作是一个整体。

2 C# 基本语法

C# 是一种面向对象的编程语言。在面向对象的编程中,程序由各种对象组成,对象之间可以通过方法进行交互。相同种类的对象通常具有相同的类型,或者说相同种类的对象都在相同的 class 中。

2.1 using 关键字

以 using 关键字开头的一行代码(例如:using System;)可以称为一条 using 语句,几乎所有的 C# 程序都是以 using 语句开头的。
using 语句主要用来引入程序中的命令空间,而且一个程序中可以包含多个 using 语句。

2.2 class 关键字

class 关键字用来声明一个类,后面是类的名字,class 关键字与类名之间使用一个空格分隔。

2.3 C#中的注释

注释用于对代码进行解释说明,在编译 C# 程序时编译器会忽略注释的内容。C# 中有单独注释和多行注释两种:

多行注释

多行注释以/* 开头,并以*/结尾,/**/ 之间的所有内容都属于注释内容。

单行注释

单行注释由//符号开头,需要注意的是单行注释没有结束符,而且只对其所在的行有效,//符号之后所有的内容都属于注释内容。

2.4 成员变量

成员变量是用来存储类中要使用的数据或属性的。

2.5 成员函数

成员函数(也可以称为成员方法)是执行特定任务的语句集,一个类的成员函数需要在类中声明。

类的实例化

通过一个已有的类(class)创建出这个类的对象(object)的过程叫做类的实例化。类的实例化需要使用 new 关键字。

标识符

标识符是用来为类、变量、函数或任何其他自定义内容命名。C# 中的标识符的定义规则如下所示:

  • 标识符必须以英文字母A-Z、a-z开头,后面可以跟英文字母A-Z、a-z,数字0-9或下划线_;
  • 标识符中的第一个字符不能是数字;
  • 标识符中不包含空格和特殊符号,例如? - + ! @ # % & ^ * () [] {} . ; : " ' / \,但是可以使用下划线_
  • 标识符不能是 C# 关键字。

3 C# 关键字

C# 中的关键字是编译器预定义好的一些单词,也可以称为保留字或者保留标识符,这些关键字对编译器有特殊的意义,不能用作标识符。但是,如果你非要使用的话也不是没有办法,只需要在关键字前面加上@前缀即可,例如@if就是一个有效地标识符,而if则是关键字。

在 C# 中,有些关键字在代码的上下文中具有特殊的意义,例如 get 和 set ,这样的关键字被称为上下文关键字(contextual keywords)。一般来说,C# 语言中新增的关键字都会作为上下文关键字,这样可以避免影响到使用旧版语言编写的 C# 程序。

4 C#数据类型

C# 语言中内置了一些基本的数据类型,数据类型用来指定程序中变量可以存储的数据类型,C# 中的数据类型可以大致分为三类:

  • 值类型(Value types);
  • 应用类型(Reference types);
  • 指针类型(Pointer types)。

C# 中的值类型是从 System.ValueType 类中派生出来的,对于值类型的变量我们可以直接为其分配一个具体的值。当声明一个值类型的变量是,系统会自动分配一块内存区域用来存储这个变量的值,需要注意的是,变量所占内存的大小会根据系统的不同而有所变化。

4.1 值类型

类型 描述 范围 默认值
bool 布尔值 true or false false
byte 8位无符号整数 0-255 0
char 16 位 Unicode 字符 U + 0000 到 U+ ffff '\0'
decimal 128 位精确的十进制值,具有28~29个有效位数 ((-7.9 x 10的28次方 到 7.9 x 10的28次方) / 10的0到28次方 0.0M
double 64位双精度浮点数 0.0D
float 32位单精度浮点数 0.0F
int 32位有符号整数类型 0
long 64位有符号整数类型 0L
sbyte 8位有符号整数类型 -128到127 0
short 16位有符号整数类型 -32 768 到 32767 0
uint 32位无符号整数类型 0 到 4294967295 0
ulong 64位无符号整数类型 0 到 18,446,744,073,709,551,615 0
ushort 16位无符号整数类型 0到 65535 0

如果想要获取类型或变量的确切大小,可以使用 sizeof 方法。

4.2 引用类型

应用类型的变量中并不存储实际的数据值,而是存储的对数据(对象)的引用,换句话说就是,引用类型的变量中存储的是数据在内存中的位置。当多个变量都引用同一个内存地址时,如果其中一个变量改变了内存中数据的值,那么所有引用这个内存地址的变量的值都会改变。C# 中内置的引用类型包括 Object(对象)、Dynamic(动态)和string(字符串)。

4.2.1 对象类型(Object)

对象类型是 C# 通用类型系统(Common Type System:CTS)中所有数据类型的最终基类,Object 是System.Object 类的别名。任何类型的值都可以分配给对象类型,但是在分配值之前,需要对类型进行转换。

将值类型转换为对象类型的过程被称为“装箱”,反之将对象类型转换为值类型的过程则被称为“拆箱”。注意,只有经过装箱的数据才能进行拆箱。

4.2.2 动态类型(Dynamic)

你可以在动态类型的变量中存储任何类型的值,这些变量的类型检查是在程序运行时进行的。动态类型的声明语法如下图所示:

dunamiv <variable_name> = value;

例如:

dynamic d= 20;

动态类型与对象类型相似,但对象类型变量的类型检查是在编译时进行的,而动态类型变量的类型检查则是在程序运行时进行的。

4.2.3 字符串类型(String)

字符串类型的变量允许你将一个字符串赋值给这个变量,字符串类型需要通过 String 类来创建,string 类是System.String 类的别名,它是从对象(Object)类型中派生的。在C# 中有两种定义字符串类型的方式,分别是使用" "@" "

s示例代码如下:

//使用引导的声明方式
String str = “http://c.biancheng.net/”;
//使用@加引号的声明形式
@"http://c.biancheng.net/";

使用@" "形式声明的字符串称为“逐字字符串”,逐字字符串会将转义字符\当作普通字符对待,例如string sstr = @"C:\Windows";等价于string str = "C\\Windows";

另外,在@" "形式声明的字符串中可以任意使用换行,换行符及缩进空格都会计算在字符串的长度之中。

4.2.4 指针类型

C# 语言中的指针是一个变量,也称为定位器和指示符,其中可以存储另一种类型的内存地址。C# 中的指针与 C 或 C++ 中的指针具有相同的还能。

指针类型的声明语法如下所示:

type* identifier;

例如:

char* cptr;
int* iptr;

5 变量

变量是程序可以操作的内存区域的名称,在C#中每个变量都有自己特点的类型,这个类型确定了变量所占内存的大小、布局、取值范围以及可以对该变量执行的操作。

可以将变量当作一种通过符号(变量名)表示某个内存区域的方法,变量的值可以更改,并且可以多次重复使用。C#中的基本变量类型可以归纳为以下几种:

类型 示例
整型(整数类型) sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double
浮点型 float、double
十进制类型 decimal
布尔型 true、false
空类型 可为空值的数据类型

5.1 声明变量

声明变量的语法格式如下:

data_type variable_list;

其中,data_type 为变量的类型,可以是C#中任何有效的数据类型,也可以是我们自定义的数据类型;variable_list 为药声明的变量名称(标识符)。variable_list中可以包含多和变量名称,每个变量名之间使用逗号进行分隔,这样我们就可以同时定义多个变量,如下所示:

int i,j,l;
double a;
char b,c;
float d;

C#中变量的名称并不是可以随意定义的的,需要遵循如下所示的规则:

  • 变量中可以包含英文字母a-z,A-Z、数字0-9和下划线_;
  • 变量名只能以英文字母a-z,A-Z或下划线_开头,不能以数字开头;
  • 变量中不允许使用空格;
  • 变量名不能是任何C#中的保留字或关键字,例如char、float等。

5.2 初始化变量

C# 中变量可以通过等号后跟一个常量表达式的形式进行初始化(赋值),语法格式如下:

variable_name = value;

也可以咋变量声明时直接进行初始化,只需要在声明变量后使用等号后跟一个常量表达式即可,语法格式如下:

data_type variable_name = value;
- 注意: 正确初始化变量是一种良好的编程习惯,否则程序运行时可能会产生意外的结果。

5.3 接受用户输入的值

ReadLine()函数:是有 System 命名空间中的 Console 类提供的,使用 ReadLine() 函数可以接受来自用户输入的内容并将其存储到变量中。

示例代码如下:

using System;

namespace Variable.cs {
    class Program {
        static void Main(string[] args) {
            int a,b;
            Console.WriteLine("请示如第一个数字:");
            a = Convert.ToInt32(Console.ReadLine());
            Console.WriteLine("请输入第二个数字:");
            b = Convert.ToInt32(Console.ReadLine());
            Console.WriteLine("{0}+{1}={2}",a,b,a+b);
        }
    }
}

运行结果为:

因为使用Console.ReadLing() 接收的数据是字符串格式的,所以示例中我们需要使用 Convert.ToInt32() 函数来将用户输入的数据转换为 int 类型。

5.4 C# 中的 Lvalue 和 Rvalue 表达式

C# 中有两种表达式,分别是 Lvalue 表达式和 Rvalue 表达式。 Lvalue 和 Rvalue 一般是使用等号=进行分隔的,等号左边的叫 Lvalue,等号右边的叫 Rvalue。

  • Lvalue:又称左值,左值表达式可以出现在赋值语句的左边或右边;
  • Rvalue:又称右值,右值表达式只可以出现在赋值语句的右边。

变量名为 Lvalue 的,所以可以出现在赋值语句的左边,而数值是 Rvalue的,因此不能被赋值,不能出现在赋值语句的左边。

6 数据类型转换

数据类型转换是由 C# 以类型安全的方式执行的,转换的过程中不会导致数据的丢失,例如从较小的整数类型(int)转换到较大的整数类型(long),从派生类型转换为基类。

6.1 隐式类型转换

隐式转换不需要我们编写额外的代码,下例中演示了如何使用隐式类型转换的方式将 int 类型的数据转换成 double 类型:

int a = 10;
double b = a;
-  提示:一种数据类型(类型A),只要其取值范围完全包含在另一个数据类型(类型B)的取值范围内,那么类型A就可以隐式转换为类型 B 。基于这一特性,C# 的隐式类型转换不会导致数据丢失。

6.2 显式类型转换

显式类型转换也叫强制类型转换,这种转换需要使用(type)value的形式或者预定义函数显式的完成,显式转换需要用户明确的指定要转换的类型,而且在转换的过程中可能会造成数据丢失,例如将 double 类型转换为 int 类型。

下面通过一个示例来演示一下显式类型转换:

using System;

namespace Explicit.cs {
    class ExplicitConversion {
        static void Main(string[] args) {
            double d = 5673.74;
            int i;

            // 将 double 转换为 int
            i = (int)d;
            Console.WriteLine("转换前{0},转换后{1}",d,i);
            Console.ReadLine();
        }
    }
} 

运行结果为:

C# 中还提供了一系列内置的类型转换方法,如下所示:

方法 描述
ToBoolean 将类型转换为布尔型
ToByte 将类型转换为字节类型
ToChar 将类型转换为单个 Unicode 字符类型
ToDateTime 将类型(整数或字符串类型)转换为日期时间的结构
ToDecimal 将浮点型或整数类型转换为十进制类型
ToDouble 将类型转换为双精度浮点型
ToInt16 将类型转换为16位整数类型
ToInt32 将类型转换为32位整数类型
ToInt64 将类型转换为64位整数类型
ToSbyte 将类型转换为有符号字节类型
ToSingle 将类型转换为小浮点数类型
ToString 将类型转换为字符串类型
ToType 将类型转换为指定类型
ToUInt16 将类型转换为16位无符号整数类型
ToUInt32 将类型转换为32位无符号整数类型
ToUInt64 将类型转换为64位无符号整数类型

【示例】使用上面提供的方法,将各种类型的数据转换为字符串类型:

using System;

namespace String.cs {
    class StringConversion {
        static void Main(string[] arge) {
            int i = 75;
            float f = 53.005F;
            double d = 2345.7652;
            bool b = true;

            // 显示转换后的数据的值,转换后的数据类型及转换前的数据类型
            Console.WriteLine("{0},{1},{2}",i.ToString(),i.ToString().GetType(),i.GetType());
            Console.WriteLine("{0},{1},{2}",f.ToString(),f.ToString().GetType(),f.GetType());
            Console.WriteLine("{0},{1},{2}",d.ToString(),d.ToString().GetType(),d.GetType());
            Console.WriteLine("{0},{1},{2}",b.ToString(),b.ToString().GetType(),b.GetType());
            Console.ReadKey();
        }
    }
};

运行结果为:

7 运算符

运算符其实就是一个符号,用来告诉编译器执行特定的数学或逻辑运算,C# 中内置了丰富的运算符,大致可以分为如下几类:

  • 算数运算符
  • 关系运算符
  • 逻辑运算符
  • 位运算符
  • 赋值运算符
  • 其他运算符

7.1 算数运算符

算是运算符即完成特定算术运算的符号,C# 中支持的算术运算符如下表所示:(假设变量 A = 10,变量 B = 20)

运算符 描述 示例
+ 加法运算符,对运算符左右两边的操作数执行加法操作 A + B 值为 30
- 减法运算符,对运算符左右两边的操作数执行减法操作 A - B 值为 -10
* 乘法运算符,对运算符左右两边的操作数相乘 A * B 值为 200
/ 除法运算符,使用运算符左边的操作数除以右边的操作数 B / A 值为 2
% 取模运算符,整除后的余数 B % A 值为 0
++ 自增运算符,整数值增加1 A++ 值为 11
-- 自减运算符,整数值减少1 A-- 值为 9

注意:自增运算符和自减运算符,它们既可以放在变量的前面使用也可以放在变量的后面使用。在变量的前面时表示先进行自增或自减运算,然后再将值赋值给变量;在变量的后面时则正好相反,先将值赋给变量,然后在进行自增或自减运算。

using System;

namespace Demo.cs {
    class Demo {
        static void Main(string[] args) {
            int a = 10;
            int b = 20;

            Console.WriteLine("a + b = {0}",a + b);
            Console.WriteLine("a - b = {0}",a - b);
            Console.WriteLine("a * b = {0}",a * b);
            Console.WriteLine("a / b = {0}",a / b);
            Console.WriteLine("a % b = {0}",a % b);
            Console.WriteLine("++a 的值是 {0}", ++a);
            a = 10;
            Console.WriteLine("a-- 的值是 {0}", a--);
            a = 10;
            Console.WriteLine("a++ 的值是 {0}", a++);
            a = 10;
            Console.WriteLine("--a 的值是 {0}", --a);
            Console.WriteLine("a 的值是 {0}", a);
            Console.ReadLine();
        }
    }
}

运行结果为:

7.2 关系运算符

关系运算符用来比较运算符左右两边的操作数。

运算符 描述
== 检查两个操作数的值是否相等,如果相等则条件为真
!= 检查两种操作数的值是都相等,如果不相等则条件为真
> 检查左操作数的值是否大于右操作数的值,如果是则条件为真
< 检查左操作数的值是否小于右操作数的值,如果是则条件为真
>= 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真
<= 检查做操作输的值是否小于或等于右操作数的值,如果是则条件为真
using System;

namespace Demo.cs {
    class Demo {
        static void Main(string[] args) {
            int a = 10;
            int b = 20;

            if (a == b) {
                Console.WriteLine("a 等于 b");
            } 
            else {
                Console.WriteLine("a 不等于 b");
            }

            if (a < b) {
                Console.WriteLine("a 小于 b");
            } else {
                Console.WriteLine("a 不小于 b");
            }

            if (a > b) {
                Console.WriteLine("a 大于 b");
            } else {
                Console.WriteLine("a 不大于 b");
            }

            if (a <= b) {
                Console.WriteLine("a 小于或等于 b");
            } 

            if (a >= b) {
                Console.WriteLine("a 大于或等于 b");
            } 
        }
    }
}

运行结果为:

7.3 逻辑运算符

下面列举 C# 中支持的逻辑运算符:

运算符 描述
&& 逻辑与运算符,如果两个操作数都为真,则结果为真
|| 逻辑或运算符,如果两个操作数中有任意一个为真,则结果为真
逻辑非运算符,用来对操作数的逻辑状态·取反,如果结果为真,那么取反后则为假

7.4 位运算符

位运算符用来对二进制位进行操作,&、| 和 ^ 的真值表如下

p q p & q p | q p ^ q
0 0 0 0 0
0 1 0 1 1
1 0 0 1 1
1 1 1 1 0
运算符 描述
& 按位与,对两个操作数的二进制位进行按位与运算,即当两个数对应的二进制位均为1时,结果位为1,否则为0
| 按位或,对两个操作数的二进制位进行按位或运算,即当两个数对应的二进制有一个为1时,结果就为1,否则为0
^ 按位异或,对两个操作数的二进制位进行按位异或运算,即当两个数对应的二进制位不同是,结果为1,否则为0
~ 按位取反,该运算符具有“翻转”位效果,即 0 变成 1, 1 变成 0,包括符号位
<< 二进制左移运算符,做操作数的值向右移动右操作数指定的位数
>> 二进制右移运算符,左操作数的值向右移动右操作数指定的位数
using System;

namespace Demo1.cs {
    class Demo {
        static void Main(string[] args) {
            int a = 60;
            int b = 13;
            int c = 0;
            c = a & b;
            Console.WriteLine("a & b 的值是 {0}",c);
            c = a | b;
            Console.WriteLine("a | b 的值是 {0}",c);
            c = a ^ b;
            Console.WriteLine("a ^ b 的值是 {0}",c);
            c = ~a;
            Console.WriteLine("~a 的值是 {0}",c);
            c = a << 2;
            Console.WriteLine("a << 2 的值是 {0}",c);
            c = a >> 2;
            Console.WriteLine("a >> 2 的值是 {0}",c);
            Console.ReadLine();
        }
    }
} 

运行结果为:

7.5 赋值运算符

赋值运算符顾名思义就是用来为变量赋值的。

运算符 描述
= 最简单的赋值运算符,把右边操作数的值赋给左边的操作数
+= 加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数
-= 减且运算符,把左边操作数减去右边操作数的结果赋值给左边操作数
*= 乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数
/= 除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数
%= 求模且赋值运算符,求两个操作数的模并赋值给左边操作数
<<= 左移且赋值运算符
>>= 右移且赋值运算符
&= 按位与且赋值运算符
^= 按位异或且赋值运算符
|= 按位或且赋值运算符

7.6 其他运算符

除了上面介绍的运算符之外,C# 中还支持一些其他的重要运算符:

运算符 描述 示例
sizeof() 返回数据类型的大小 sizeof(int),将返回4
typeof() 返回 class 的类型 typeof(StreamReader);
& 返回变量的地址 &a 将得到的变量的实际地址
* 变量的指针 *a;将指向一个变量。
?: 三元(三目)运算符 a>b?X:Y;如果条件为真,则值为 X;否则值为 Y
is 判断对象是否为某一类型 if(Ford is Car) // 检查Ford是否是Car类的一个对象
as 强制转换,即使转换失败也不会抛出异常。 Object obj = new StringReader("Hello");StringReader r = obj as StringReader;

7.7 运算符的优先级

通过前面的学习我们知道运算符有不同的类型,当这些不同类型的运算符出现在同一个表达式中,就必须遵循运算符的优先级来进行运算,才能保证运算的合理性和结果的正确性、唯一性。运算符的优先级决定了表达式中各个部分执行运算的先后顺序。

运算符的优先级顺序如下表所示:

优先级 运算符 名称或含义 使用形式 结合方向 说明
1 [] 数组下标 数组名[整型表达式] 左到右
() 圆括号 (表达式)/函数名(形参表)
. 成员选择(对象) 对象.成员名
-> 成员选择(指针) 对象指针->成员名
2 - 负号运算符 -表达式 右到左 单目运算符
(type) 强制类型转换 (数据类型)表达式
++ 自增运算符 ++变量名/变量名++ 单目运算符
-- 自减运算符 --变量名/变量名-- 单目运算符
* 取值运算符 *指针表达式 单目运算符
& 取地址运算符 &左值表达式 单目运算符
逻辑运算符 !表达式 单目运算符
~ 按位取值运算符 ~表达式 单目运算符
sizeof 长度运算符 sizeof表达式/sizeof(类型)
3 / 表达式/表达式 左到右 双目运算符
* 表达式*表达式 双目运算符
% 余数(取模) 整型表达式%整型表达式 双目运算符
4 + 表达式+表达式 左到右 双目运算符
- 表达式-表达式 双目运算符
5 << 左移 表达式<<表达式 左到右 双目运算符
>> 右移 表达式>>表达式 双目运算符
6 > 大于 表达式>表达式 左到右 双目运算符
>= 大于等于 表达式>=表达式 双目运算符
< 小于 表达式<表达式 双目运算符
<= 小于等于 表达式<=表达式 双目运算符
7 == 等于 表达式==表达式 左到右 双目运算符
!= 不等于 表达式!=表达式 双目运算符
8 & 安伟宇 整型表达式&整型表达式 左到右 双目运算符
9 ^ 按位异或 整型表达式^整型表达式 左到右 双目运算符
10 | 按位或 整型表达式|整型表达式 左到右 双目运算符
11 && 逻辑与 表达式&&表达式 左到右 双目运算符
12 || 逻辑或 表达式||表达式 左到右 双目运算符
13 ?: 条件运算符 表达式1?表达式2:表达式3 右到左 三目运算符
14 = 赋值运算符 变量=表达式 右到左
/= 除后赋值 变量/=表达式
*= 乘后赋值 变量*=表达式
%= 取模后赋值 变量%=表达式
+= 加后赋值 变量+=表达式
-= 减后赋值 变量-=表达式
<<= 左移后赋值 变量<<=表达式
>>= 右移后赋值 变量>>=表达式
&= 按位与后赋值 变量&=表达式
^= 按位异或后赋值 变量^=表达式
|= 按位或后赋值 变量|=表达式
15 , 逗号运算符 表达式,表达式,··· 左到右 从左到右顺序运算

8 常量

常量和前面所说的变量类似,唯一不同的是敞亮的值在程序的编译阶段就已经确定了,而且在程序的运行期间不允许修改,常量可以是任意基本数据类型,例如整数常量、浮点常量、字符串常量等等。

8.1 定义常量

常量需要使用 const 关键字定义,语法格式如下所示:

const data_type constant_name = value;

其中,data_type 为常量的数据类型;constant_name 为常量名(类似于变量名);value 为常量的值。

using System;

namespace Demo2.cs {
    class Demo2 {
        static void Main(string[] args) {
            const double pi = 3.14;

            double r;
            Console.WriteLine("本程序可以计算圆的面积,请输入一个数作为圆的半径:");
            r = Convert.ToDouble(Console.ReadLine());

            double areaCircle = pi * r * r;
            Console.WriteLine("半径为:{0},圆的面积为:{1}",r,areaCircle);
            Console.ReadKey();
        }
    }
}

运行结果为:

8.2 整数常量

整数常量可以是八进制、十进制或者十六进制,可以使用前缀指定具体的进制,例如0x0X表示十六进制,0表示八进制,没有前缀则表示十进制。

除了前缀外,整数常量还可以包含后缀,后缀可以是 U 和 L 的结合,U 和 L 分别表示 unsigned 和 long。后缀既可以大写也可以小写,而且可以以任意顺序进行组合,但是不能重复。

整数常量示例:

85    // 合法:十进制常量
0213  // 合法:八进制常量
0x4b  // 合法:十六进制常量
30    // 合法:int 类型常量
30u   // 合法:无符号 int 类型常量
30l   // 合法:long 类型常量
30ul  // 合法:无符号 long 类型常量
068   // 非法:8 不是一个八进制数字
032UU  // 非法:后缀不能重复

8.3 浮点常量

浮点常量由整数部分、小数点、小数部分和指数部分组成。你可以使用小数或者指数形式来表示浮点常量。

下面为一些浮点常量示例:

3.14159       // 合法
314159E-5L    // 合法
510E         // 非法:不完全指数
210f         // 非法:没有小数或指数
.e55         // 非法:缺少整数或小数

当使用小数形式表示浮点常量时,必须包含小数点、指数或同时包含两者。当使用指数形式表示浮点常量是,必须包括整数部分、小数部分或同时包含两者。有符号的指数使用 e 或 E 表示。

8.4 字符常量

字符常量需要使用单引号括起来,类似于定义字符串类型的变量,例如'X'。一个字符常量可以是一个普通字符(例如'X')、转义序列(例如'\t')或 Unicode 字符(例如'\u02C0')。

在C#中,有些字符前面带有一个反斜杠,这样的字符具有特殊含义,例如\n用于表述换行符、\t表示制表符。下表中列举了一些常用的转义字符:

转义序列 含义
\ \字符
' '字符
" "字符
? ?字符
\a Alert或bell
\b 退格键(Backspace)
\f 换页符(From feed)
\n 换行符(Newline)
\r 回车
\t 水平制表符 tab
\v 垂直制表符 tab
\ooo 一到三位的八进制字符
\xhh... 一个或多个数字的十六进制字符

8.5 字符串常量

字符串常量需要使用双引号" "或者@" "引起来。字符串常量与字符常量相似,可以是纯字符、转义序列或 Unicode 字符。

下面列举一些字符串常量(下面各种形式的字符串常量都表示相同的字符串)

"C语言中文网";    
@"C语言中文网";   
"C语言 \t 中文网";
@"C语言 \t 中文网";
@"C语言
中文网";

9 语句

9.1 if else:条件判断语句

在 C# 编程中,if 语句主要用于条件判断,C# 中支持多种类型的 if 语句:

  • if 语句
  • if else 语句
  • if else if 语句

9.1.1 if 语句

C# 中的 if 语句用于条件判断,其中包含一个布尔表达式,后面跟随者若干要执行的代码,当布尔表达式为真实,后面跟随的代码就会执行,if 语句的语法格式如下:

if(布尔表达式) {
  表达式为真时要执行的代码;
}

if 语句的执行流程如下图所示:

9.1.2 if else 语句

C# 的 if else 语句同样用于条件判断,它比 if 语句中多处了一个 else 语句,当布尔表达式为假时,执行 else 语句块中的代码,语法格式如下所示:

if(布尔表达式) {
  表达式为真实要执行的代码;
}  else {
  表达式为假时要执行的代码;
}

if else 语句的执行流程如下图所示:

9.1.3 if else if 语句

C# 的if else if 语句其实就是一个 if 语句后面跟随着若干个 else if else 语句,语句中可以包含对各条件表达式,程序会依次判断这些条件表达式,当条件表达式为真时执行后面语句块中的代码,如果没有为真的条件表达式则执行 else 语句块中的代码,其语法格式如图所示:

if(布尔表达式1) {
  布尔表达式1为真时要执行的代码;
} else if(布尔表达式2) {
  布尔表达式2为真时要执行的代码;
} else if(布尔表达式3) {
  布尔表达式3为真时要执行的代码;
}
···
else {
  所有布尔表达式都为假是要执行的代码;
}

需要注意的是,当布尔表达式为真,且成功执行它后面语句块中的代码后,会跳出 if else if 语句,语句中的其他部分不会再被执行。if else if 语句的执行流程如下图所示:

9.2 switch 语句

C# 中的 Switch 语句有些类似于《if else if语句》,都可以根据表达式执行某个语句块,其语法格式如下:

switch(表达式) {
  case value1:     // 表达式的值为 value1 时,要执行的代码
    break;
  case value2:     // 表达式的值为 value2 时,要执行的代码
    break;
  ··· ···
  default:        // 没有与表达式相匹配的值时,则执行的代码
    break;
}

使用 switch 语句时必须遵守一下规则:

  • switch 语句中表达式的值必须是一个整型或者枚举类型;
  • 在一个 switch 语句中可以有任意数量的 case 语句,每个 case 关键字后面要跟一个与表达式比较的值和一个冒号;
  • case 关键字后面的值必须与 switch 中表达式的值具有相同的数据类型,并且必须是一个常量(也可以理解为是一个固定的值,不会随程序的运行发生改变);
  • 当表达式的值等于 case 中的值时,就会执行 case 后面的语句,在遇到 break 关键字时停止;
  • 当遇到 break 关键字时,switch 语句会停止运行,并跳转到 switch 语句以外的下一行代码继续运行;
  • 并不是每一个 case 语句后面都需要包含 break 关键字,如果 case 语句为空(case 语句后面没有要执行的代码),则可以不包含 break 关键字,这时程序会继续执行后面的 case语句,直至遇到 break 关键字为止;
  • C# 不允许从一个 case 语句连续执行到下一个 case 语句,因此如果 case 语句中包含要执行的语句,就必须包含 break 关键字或者其他跳转语句;
  • 一个 switch 语句的末尾可以有一个可选的 default (默认选项),当所有 case语句都不能与表达式相匹配时则会执行 default 部分中的代码,而且 default 中的 break 语句可以省略;
  • C# 不支持从一个 case 语句跳转到另一个 case语句,如果要从一个 case 语句跳转到另一个 case 语句的话可以使用 goto 语句,例如 goto default

switch 语句的执行流程如下图所示:

using System;

namespace Demo3.cs {
    class  Demo3 {
        static void Main(string[] args) {
            Console.WriteLine("请输入学生考试的成绩(0~100的整数)");
            int points = Convert.ToInt32(Console.ReadLine());
            switch (points / 10) {
                case 10:
                    Console.WriteLine("优秀");
                    break;
                case 9:
                    Console.WriteLine("优秀");
                    break;
                case 8:
                    Console.WriteLine("良好");
                    break;
                case 7:
                    Console.WriteLine("及格");
                    break;
                case 6:
                    Console.WriteLine("及格");
                    break;
                default:
                    Console.WriteLine("不及格");
                    break;
            }
        }
    }
}

运行结果为:

9.3 循环

在某些情况下,我们可能需要重复执行某些代码,这时就需要用到 C# 中的循环语句,C# 中支持 for 循环、foreach 循环、while 循环和 do while 循环等循环语句。

9.3.1 for 循环

单循环

使用 for 循环可以重复执行一部分代码,而且重复的次数是可以设定的,其语法格式如下所示:

for(初始化语句;判断条件;迭代器) {
  // 循环主体(要执行的代码)
}

for 循环语句的执行流程如下所示:

  • 首先执行初始化语句(通常是一个变量),并且只执行一次,在某些情况下初始化语句可以省略,只保留后面的分号即可;
  • 接下来进行条件判断,如果为true,则执行循环主体,如果为false,则跳出 for 循环,执行 for 循环以外的代码;
  • 循环主体执行完成后,更新迭代器的值(增加或减少),然后再进行条件判断,如果为真则再次执行寻循环体,重复执行此步骤,直至判断条件为假,跳出循环。

for 循环的执行流程如下图所示:

嵌套循环

在 C# 中,循环语句还可以嵌套使用,也就是说我们可以在一个 for 循环内再使用一个或多个 for 循环。

示例:使用 for 循环输出九九乘法表:

using System;

namespace Multiplication.cs {
    class Multiplication {
        static  void Main(string[] args) {
            for(int i = 1; i <= 9; i++) {
                for(int j = 1; j <=i; j++) {
                    Console.Write("{0} x {1} = {2}\t",j,i,i*j);
                }
                Console.WriteLine();
            }
        }
    }
}

运行结果为:

无限循环

for 循环中,如果判断条件永远不会假,那么循环将变成无限循环(也叫死循环),我们在定义循环语句时应尽量避免这种情况的出现。

9.3.2 while 循环

在 C# 中,while循环用于迭代一部分程序,特别是在迭代的次数不固定的情况下,建议使用 while 循环而不是 for 循环,while循环的语句格式如下所示:

while(表达式) {
  循环体;  // 要执行的代码
}

其中:循环体可以是一个单独的语句,也可以是多条语句组成的代码块,当表达式的值为真时,循环体会一直执行下去。while 循环的执行流程如下图所示:

与 do while 循环相比, while 循环有一个特点,那就是 while 循环可能一次也不会执行。因为当表达式判断结果为假时会直接跳出去循环,执行循环之后的代码。

与 for 循环相同,while 循环也可以嵌套使用。

9.3.3 do while 循环

在 C# 中,do while 循环同样用于多次迭代一部分程序,但他与我们前面学习的 for 循环和 while 循环不同,for 循环和 while 循环会在循环开始之前先判断表达式的结果,只有表达式结果为真时才能开始循环,而 do while 循环会先执行一遍循环主体中的代码,然后再判断表达式的结果。也就是说,不论表达式的结果如何,do while 循环至少会执行一次。

do while 循环的语法表达式如下:

do {
  循环主体;   // 要执行的代码
}while(表达式);

注意:与 for 循环和 while 循环不同,do while 循环需要以分号;结尾。

do while 循环的执行流程如下图所示:

do while 循环中,程序会先执行do{}中的循环主体,执行完成后再去判断while()中的表达式,如果表达式为真,则继续执行do{}中的循环主体,如果表达式为假,则跳出 do while 循环。

与for循环和 while 循环一样, do while 循环也可以嵌套使用。

9.3.4 foreach 循环

除了前面几种循环之外,C# 同样也支持 foreach 循环,使用 foreach 可以遍历数组或者集合对象中的每一个元素,其语法如下:

foreach(数据类型 变量名 in 数组或集合对象) {
  语句块;
}

foreach 会在每次循环的过程中,一次从数组或集合对象中取出一个新的元素放到foreach()里定义的变量中,直到所有元素都成功取出后退出循环。

示例:使用for 循环定义一个包含1~100以内所有数字的数组,然后使用 foreach 循环计算 1~100以内的数字之和:

using System;

namespace Foreach.cs {
    class Foreach {
        static void Main(string[] args) {
            int[] arr = new int[100];
            for(int i = 0; i < 100; i++) {
                arr[i] = i + 1;
            }
            int sum = 0;
            foreach (int j in arr) {
                sum = sum + j;
            }
            Console.WriteLine("1~100以内数字的和为:{0}", sum);
            Console.ReadLine();
        }
    }
}

运行结果为:

9.3.5 break、continue、goto:跳出循环

在使用循环语句时,并不是必须等待循环完成后才能退出循环,也可以主动退出循环,C# 提供了 break、continue、goto 三种方式跳出循环,下面分别介绍一下。

1、break

break 语句不仅可以用来终止 switch 语句,在循环语句中使用时还可以用来跳出循环,执行循环外的下一条语句。

如果是在嵌套循环中使用,例如在内层的循环中使用 break 语句,那么程序只会跳出内层的循环,并不会影响到外层循环的执行。break 语句的执行原理如下图所示:

2、continue

C# 中 continue 语句的工作原理与 break 语句类似,但是 continue 语句并不会跳出整个循环,而是跳过本次循环继续执行下一次的循环。continue 的执行原理如下所示:

3、goto

C# 中的 goto 语句也称为跳转语句,使用它可以控制程序跳转到指定的位置执行。不过并不建议在程序中多次使用 goto 语句,因为它会使程序变得更加复杂。goto 语句的语法格式如下:

goto Labels;
  语句块1;
Labels:
  语句块2;

想要使用 goto 语句来跳转程序,必须先在想要跳转的位置定义好一个标签(Labels),标签名称的定义和变量名类似,然后使用goto标签名;即可使程序跳转到指定位置执行。如上面语法中所示,程序会跳过“语句块1”直接执行“语句块2”。

提示:goto 语句并不限于在循环中使用,其它的情况也可以使用。但是,goto 语句不能从循环外跳转到循环语句中,而且不能跳出类的范围。

示例:使用 goto 语句将程序跳转到指定位置执行:

using System;

namespace Goto.cs {
    class Goto {
        static void Main(string[] args) {
            int count = 1;
            login:
                Console.WriteLine("请输入用户名");
                string username = Console.ReadLine();
                Console.WriteLine("请输入密码");
                string userpwd = Console.ReadLine();
            if(username == "Goto" && userpwd == "123456") {
                Console.WriteLine("登录成功");
            } else {
                count++;
                if(count > 3) {
                    Console.WriteLine("用户名或密码错误次数过多!退出");
                } else {
                    Console.WriteLine("用户名或密码错误");
                    goto login; // 返回login标签处重新输入用户名密码
                }
            }
        }
    }
}

运行结果为:

10 函数/方法详解

C# 中函数(也可以称为方法)是一段具有签名(有函数名、参数类型和参数修饰符组成的函数信息)的代码块,可以用来实现特定的功能。一般情况下一个函数由一下几个部分组成:

  • 访问权限修饰符:用于指定函数对一个类的可见性;
  • 返回值类型:用于指定函数返回值的类型;
  • 函数名称:用于进行函数调用的唯一名称;
  • 参数列表:在调用函数时需要传递给函数的参数,参数列表是可选的,可以为空;
  • 函数主体:其中包含了实现函数功能的若干代码。

10.1 函数声明

C# 中声明函数的语法格式如下:

访问权限修饰符 返回类型 函数名称(参数列表) {
  函数主体;
  返回语句;
}

返回语句,用来返回数据。
另外需要注意的是,访问权限修饰符、参试列表和返回语句是可选的,可以省略。

10.2 函数调用

想要调用我们定义好的函数,首先需要将函数所在的类实例化为对象,然后通过对象.函数名()的形式即可调用指定的函数,这里有几点需要注意:

  • 若函数在定义时参数列表中定义了若干参数,那么在调用时也应该在函数名后面的括号中填入相应数量的参数,并且与参数列表中的参数类型一一对应;
  • 若函数在定义时没有定义参数列表,那么在调用函数时也不需要在函数名后面填入参数;
  • 对于有返回值的函数,在调用函数时可以使用一个变量(可选)来接受函数的返回值,变量的类型要与函数返回值的类型相同。

提示:肉调用同一个人类中静态函数(使用 static 修饰的函数),则可以省略实例化对象的过程,直接使用函数名()的形式调用。

10.3 没有参数和返回值的函数

C# 中,如果函数不需要返回任何内容,则可以在定义函数时使用 void 来修饰返回值类型,示例代码如下:

using System;

namespace Demo4.cs {
    class Demo {
        static void Main(string[] args) {
            Demo Obj = new Demo();  // 实例化当前类的对象
            Obj.Output();    // 调用定义好的 Output 函数
        }

        // 定义一个没有返货值得函数

        public void Output() {
            Console.WriteLine("http://www.Demo.cs/");
        }
    }
}

运行结果如下:

10.4 有参数但没有返回值的函数

如前面介绍的那样,函数可以接收一个或多个数据作为参数,并在函数内部使用或处理传入的参数,示例代码如下:

using System;

namespace Demo5.cs {
    class Demo {
        static void Main(string[] args) {
            string str = "http://c.biancheng.net";
            Demo Obj = new Demo();   // 实例化当前类的对象
            Obj.Output(str);  // 调用定义好的 output 函数,并将字符串 str 传递给函数
        }

        // 定义一个没有返回值的函数,该函数可以接收一个参数

        public void Output(string message) {
            Console.WriteLine(message);
        }
    }
}

运行结果为:

10.5 有参数且有返回值的函数

一个函数可以具有零个或任意数量的参数,也可以返回指定的数据。

示例:创建一个包含一个参数的函数,在函数中将传入的字符串拼接成一个新的字符串,并将新的字符串返回。

using System;

namespace Demo6.cs {
    class Demo {
        static void Main(string[] args) {
            // 十里湖当前类的对象
            Demo Obj = new Demo();
            // 调用定义好的 Output 函数,将字符串传递给函数,并使用 msg 接收函数的返回值
            string msg = Obj.Output("http://c.biancheng.net/");
            Console.WriteLine(msg);
        }
        /* 定义一个函数,该函数可以接收一个字符串参数,
        并返回一个字符串 */
        public string Output(string message)  {
            string str = "欢迎访问:" + message;
            return str;
        }
    }
}

运行结果为:

10.6 类中的静态函数

在 C# 中静态函数指的是,在一个类中使用static 修饰的函数,调用静态函数比调用普通函数要简单很多,只需要函数名即可:

using System;

namespace Demo7 {
    class Demo {
        static void Main(string[] args) {
            // 调用类中的静态函数
            string msg = Output("http://c.biancheng.net/");
            Console.WriteLine(msg);
        } 
        /* 定义一个函数,该函数可以接受一个字符串参数,
        并返回一个字符串 */
        static string Output(string message) {
            string str = "欢迎访问:" + message;
            return str;
        }
    }
}

运行结果为:

11 封装

C# 是一门面向对象的编程语言,面向对象编程语言有三大特性,分别是封装、继承和多态。所谓封装就是将一个或多个项目(函数)集合在一个单元中,这个单元称之为类,我们可以根据需要通过访问权限修饰符来设定类中成员的范围和可见性。C# 中的访问权限修饰符有以下几种:

  • public:公共的,所有对象都可以访问,程序集就是命名空间;
  • private:私有的,类的内部才可以访问;
  • internal:内部的,同一个程序集的对象可以访问,程序及就是命名空间;
  • protected:受保护的,类的内部或类的父类和子类中可以访问;
  • Protected internal:protected 和internal 的并集,符合任意一条都可以访问。

11.1 public

类中使用 public 访问权限修饰符修饰的成员变量或成员函数可以在其他函数和对象中使用,我们可以从类的外部访问类中的公共成员(使用 public 修饰的类成员)。

using System;

namespace c.biancheng.net {
    class Demo {
        class Rectangle {
            // 成员变量
            public double width, length;

            public double GetArea() {
                return width * length;
            }

            public void Display() {
                Console.WriteLine("长方形的长:{0}", length);
                Console.WriteLine("长方形的宽:{0}", width);
                Console.WriteLine("长发形的面积:{0}",GetArea());
            }
        }
        static void Main(string[] args) {
            Rectangle Obj = new Rectangle();
            Obj.width = 5.5;
            Obj.length = 3;
            Obj.Display();
            Console.ReadLine();
        }
    }
}

运行结果为:

上面的示例中,成员变量 length 和 width 都是使用 public 修饰的,所以可以在 main 函数中使用 Rectangle 类的实例来进行访问。

11.2 private

类中使用 private 访问权限修饰符的成员变量或成员函数不能在其他函数或对象,即使是类的实例也不能访问这个类中的私有成员,只有同属一个类的函数才可以访问这个类的私有成员。

using System;

namespace c.biancheng.net {
    class Demo1 {
        class Rectangle {
            // 成员变量
            private double width, length;

            public void AcceptDetails() {
                Console.WriteLine("请输入长方形的长度:");
                length = Convert.ToDouble(Console.ReadLine());
                Console.WriteLine("请输入长方形的宽度:");
                width = Convert.ToDouble(Console.ReadLine());
            }
            public double GetArea() {
                return width * length;
            }
            public void Display() {
                Console.WriteLine("长方形的长:{0}", length);
                Console.WriteLine("长方形的宽:{0}", width);
                Console.WriteLine("长方形的面积:{0}",GetArea());
            }
        }
        static void Main(string[] args) {
            Rectangle Obj = new Rectangle();
            Obj.AcceptDetails();
            Obj.Display();
            Console.ReadLine();
        }
    }
}

运行结果为:

上面示例中,成员变量 length 和 width 使用 private 修饰,因此无法通过 Demo1 类中的 Main 函数访问,只能通过 Rectangle 类中的成员函数 AcceptDetails() 和 Display() 来访问这些变量。又因为 Rectangle 中的成员函数 AcceptDetails() 和 Display() 是使用 public 修饰的,因此可以使用 Rectangle 类的实例 Obj 来调用它们。

11.3 protected

类中使用 protected 访问权限修饰符修饰的成员变量和成员函数可以在其子类中访问,也就是说基类(父类)中使用 protected 访问权限修饰符修饰的成员变量和成员函数可以在其子类中访问,这样有助于实现继承。

11.4 internal

类中使用 internal 访问权限修饰符修饰的成员变量和成员函数可以在当前程序集中的其他函数和对象中使用。换句话说,任何使用 internal 修饰的成员都可以被同一命名空间下的任何类或方法访问。

11.5 protected internal

类中使用 protected internal 访问权限修饰符修饰的成员可以在本类、派生类或者包含该类(使用 using 引入)的程序集中访问,在实现继承时也使用此方法。

12 值传递、引用传递、输出传递

通过前面的学习我们知道,在调用带参函数时,需要将参数传递给函数。

参数分为形参和实参,下面介绍一下什么是形参和实参:

  • 形式参数:在定义函数阶段参数列表中定义的参数称之为形式参数,简称新参,可以将它看作变量的名称,它没有具体的值,只是用来接收函数调用时传递过来的数据。
  • 实际参数:在函数被调用是传递给函数的参数称之为实际参数,简称实参,可以将它看作变量的值,用来为形参赋值。

参数可以通过三种方式传递给函数:值传递、引用传递、输出传递

  • 值传递:值传递会复制参数的实际值并赋值给函数的形式参数,实参和形参使用的是两个不同位置中的值,当形参的值发生改变时,不会影响实参的值,从而保证了实参数据的安全
  • 引用传递:引用传递会复制参数的内存位置并传递给形式参数,当形参的值发生改变时,同时也会改变实参的值
  • 输出传递:输出传递可以一次放回多个值

12.1 值传递

值传递是将参数传递给函数的迷人方式,值传递的本质就是将实参的副本(将实参的值复制一份)传递给函数的形参。当调用函数时,会使用实参为每个形参赋值,并为每个形参创建一个新的存储位置,由于形参和实参指向不同的内存位置,所以无论是修改实参的值还是修改形参的值都不会对彼此产生影响。

12.2 引用传递

引用传递是对变量内存位置的引用。与值传递不同,使用引用传递的形式传递参数时,并不会为形参创建新的内存地址,而是与实参共同指向相同的内存地址。正因为如此,当修改形参是值时,时间的值也会被修改。

12.3 输出传递

使用return 语句可以从函数中返回一个值,但是使用输出传递则可以从函数中一次性返回多个值。输出传递与引用传递相似,不同之处在于输出传递是将数据从函数中传输出来而不是传输到函数中。

13 nullable:可空类型

在 C# 1.x的版本中,一个值类型的变量是不可以被赋值为 null (空值)的,否则会产生异常。而在 C# 2.0中,新增了一个nullable类型,可以使用nullable 类型定义包含null值的数据,例如,你可以在nullable (可为空的 Int32 类型)类型的变量中存储 -2147483648 到 2147483647 之间的任何值或者 null。同样,你可以在nullable (可为空的 bool 类型)类型的变量中存储 TRUE、false 或 null。

声明可空类型的语法如下:

data_type? variable_name = null;

其中,data_type为要声明的数据类型,后面紧跟一个问号;variable_name 则为变量的名称。

Null 合并运算符(??)

null 合并运算符用于定义可空类型和引用类型的默认值。如果此运算符的做操作数不为 null,那么运算符将返回左操作数,否则返回右操作数。李彪表达式a??b中,如果 a 不为空,那么表达式的值则为 a,反之则为 b。

注意:null 合并运算符左右两边操作数的类型必须相同,或者右操作数的类型可以隐式的转换为左操作数的类型,否则将编译错误。

14 数组

14.1 数组

数组是一个用来存储相同类型数据的、固定大小的、具有连续内存位置的顺序集合。数组中的每个元素都对应一个索引值,索引从0开始依次递增,我们可以通过索引来访问数组中的指定元素。

所有数组都是由连续的内存位置组成,最低的内存地址对应第一个元素,最高的内存地址对应最后一个元素,如下图所示:

14.1.1 声明数组

声明一个数组的语法格式如下:

data_type[] aeeay_name;

其中,data_type 用来指定数组中元素的类型;[]用来指定数组的维度;array_name 为数组的名称。

示例代码如下:

int[] array1;        //声明一个整型数组
double[] array2;      // 声明一个浮点型数组

14.1.2 初始化数组

仅仅是声明数组还不够,数组只能进过初始化后才可以为其中的每个元素赋值。因为数组时引用类型的,所以需要使用 new 关键字对数组进行初始化操作,例如:

int[] array1;   // 声明一个整型数组
array1 = new int[10];   // 初始化数组array1
double[] array2;     // 声明一个浮点型数组
array2 = new double[5];  // 初始化数组 array2

另外,数组的声明和初始化还可以放在一起进行,如下所示:

int[] array1 = new int[10];  // 初始化一个长度为 10 的整型数组
double[] array = new double[5]; // 初始化一个长度为 5 的浮点型数组

提示:初始化数组的过程中,new int[10] 中 [] 里面的数字代表数组的长度,也就是数组中最多可以存放多少个元素,我们可以根据需要来设定数组的长度。

14.1.3 为数组元素赋值

我们可以使用数组的索引来为数组中的各个元素赋值,如下所示:

int[] arr = new int[10];
arr[0] = 10;
arr[1] = 11;

单独为数组中的各个元素赋值太过麻烦了,我们可以在声明数组时直接为数组赋值,只需要将数组中的每个元素依次放入到一个{}中,并将每个元素使用,分隔开即可,如下所示:

double[] arr1 = {32.1,432.1,64.0,54.6};
int[] arr2 = {1,2,3,4,5,6,7,8,9,0};

使用上面的方法并不用提前设定数组的长度,如果想要指定数组的长度,只需要像下面这样即可:

double[] arr1 = new double[4]{32.1,432.1,64.0,54.6};
int[] arr2 = new int[10]{1,2,3,4,5,6,7,8,9,0};

也可以省略数组中的长度,如下所示:

double[] arr1 = new double[]{32.1,432.1,64.0,54.6};
int[] arr2 = new int[]{1,2,3,4,5,6,7,8,9,0};

数组也可以像变量一样,使用一个定义好的数组为另一个相同类型的数组赋值,这种情况下,两个数组将指向相同的内存地址,如下所示:

posted @ 2022-12-16 11:33  空岛迷梦  阅读(217)  评论(0编辑  收藏  举报
// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css