类
通过类能很好地体现面向对象语言中的三大特性——封装、继承、多态。
【一】、类的定义
类定义的语法如下:
类的访问修饰符 修饰符 类名 { 类的成员 }
① 类的访问修饰符 —— 用于设定对类的访问限制
类的访问修饰符有2个
1)public : 可以在任何项目中访问改该类
2)internal/不写:只能在当前项目中访问该类
② 修饰符 —— 对类本身特点的描述
包括 abstract、sealed 和 static
③ 类名
类名和常规的取变量名类似,一般在取名的时候,最好能表现出该类的功能。在同一个命名空间下,类名必须是唯一的。
④ 类成员 —— 在类中能定义的元素
主要包括字段、属性、方法
【二】、类的成员
类中的成员包括字段、属性、方法。每个类成员在定义时需要指定访问修饰符、修饰符。
通用——访问修饰符
类中成员的访问修饰符有 4 个
1)public —— 成员可以被任何代码访问
2)private —— 成员仅能被同一个类中的代码访问
如果在类成员前没有使用任何修饰符,就默认为private
3)internal —— 成员仅能别同一个项目中的代码访问
4)protected—— 成员只能由类或者派生类中的代码访问
派生类是在继承中涉及
类的成员 —— 字段 and 属性
字段的定义与变量和常量的定义类似,只是在变量或常量前面可以加上访问修饰符、修饰符。
定义字段的语法形式如下:
访问修饰符 修饰符 数据类型 字段名;
字段的修饰符
修饰字段时通常用两个修饰符,即 readonly (只读)和static (静态的)
1)readonly —— 只能读取该字段的值而不能给字段赋值
2)static —— 静态字段,可以直接通过类名访问
注意常量不能使用static修饰符 修饰
get访问器 和 set访问器
属性经常与字段连用,并提供了 get 访问器和 set 访问器,分别用于获取或设置字段的值。
知识普及一:
get访问器和set访问器的使用与方法的使用其实蛮类似的,可以在操作字段的时候,根据一些规则和条件来设置获取字段的值。
知识普及二:
可以选择性去除get访问器或者set访问器。
1)get{}
get访问器,用于设置获取属性的值,在最后需要使用return 返回一个与该属性数据类型想兼容的值。
若在属性定义中忽略了该访问器,则不能在其他类中获取私有类型的字段值,所以有时候也称为只写属性
2)set{}
set访问器用于设置字段的值,这里需要使用一个特殊的值value,把它用来为字段赋值。
在set访问器省略后,无法在其他类中给该字段赋值,所以也称为只读属性。
① 属性设置:
语法:
public 数据类型 属性名 { get { 获取属性的语句块; return 值; } set { 设置属性得到语句块; } }
Tips: 由于属性都是针对某个字段赋值,因此属性的名称通常是将字段中每个单词的首字母大写。例如定义了一个名为 name 的字段,属性名则为 Name。
【随堂演练】定义一个图书信息类(Book),在类中定义图书编号(id)、图书名称(name)、图书价格(price)3 个字段,并分别为这 3 个字段设置属性,其中将图书名称设置为只读属性。
参考代码
using System; namespace OOPDemo_1 { class Book { private int id; private string name; private double price; //设置图书编号属性 public int Id { get { return id; } set { id = value; } } //设置图书名称属性 //根据要求,将图书的书名设置为只读属性 public string Name { get { return name; } } //设置图书价格属性 public double Price { get { return price; } set { price = value; } } } }
② 自动属性设置
定义语法:
public 数据类型 属性名{get;set;}
参考代码
public int Id{get; set;} public string Name{get; set;} public double Price{get; set;}
使用注意点一:
如果使用自动属性设置的方式来设置属性,大括号内不需要指定字段。
但是
如果想要把某个属性设置为只读属性,可以直接省略set访问器即可实现。
public int Id{get;}
如果此时还想要给某个属性值赋值,可以这种操作
//只读属性 public int Id{get;}=1; //常规 public int Id{get; set;}=1;
使用注意点二:
自动生成属性的方法不能省略get访问器,如果不允许其他类来访问该属性值,可以通过加private修饰符来实现。
public int Id{private get; set;}
类的成员 —— 方法
常规观念中的方法
主方法 Main()是执行程序的入口和出口
方法是将完成同一功能的内容放到一起,方便书写和调用的一种方式。也体现了面向对象语言中的封装性。
定义方法的语法:
访问修饰符 修饰符 返回值类型 方法名(参数列表) { 语句块; }
1) 访问修饰符
所有修饰类成员的访问修饰符也可以用来修饰符方法。假如省略不写,则默认为private
2) 修饰符
3)返回值类型
用于在调用方法后得到返回结果,返回值可以是任意的数据类型,如果指定了返回值类型,必须使用 return 关键字返回一个与之类型匹配的值。
如果没有指定返回值类型,必须使用 void 关键字表示没有返回值。
4)方法名
方法名的命名是以 Pascal 命名法为规范的。支持重名,因为有方法的重载
5)参数列表
在方法中允许有 0 到多个参数,如果没有指定参数也要保留参数列表的小括号。
参数的定义形式是数据类型 参数名,如果使用多个参数,多个参数之间需要用逗号隔开。
构造方法
① 构造方法的名字是与类的名称相同的
创建类的对象是使用类名 对象名 = new 类名()的方式来实现的。
实际上,此处的类名()的形式调用的是类的构造方法
对于创建对象这块,假如在new 的类中没有自定义构造方法,此时会使用系统默认生成的一个不带参数的构造方法。
② 构造方法的定义语法
访问修饰符 类名 (参数列表) { 语句块; }
这里构造方法的访问修饰符通常是public类型的,这样在其他类中都可以创建该类的对象
如果将访问修饰符设置成private类型的,则无法创建该类的对象。
构造方法中的参数与其他方法一样,都是 0 到多个参数。
Tips:正是因为其可带参数,因此可以将一些类成员初始化的操作放到构造方法中去完成,这种既可以创建对象,也可以初始化对象
折构方法
折构方法了解就好,析构方法则是在垃圾回收、释放资源时使用的。
暂时和咱们有点遥远。先积累。
折构方法定义语法
~类名() { 语句块; }
在调用重载的方法时系统是根据所传 递参数的不同判断调用的是哪个方法。
方法的重载还是比较容易理解的,想着重拓展一下关于方法参数的知识
① 实参和形参
方法中的参数分为实际参数和形式参数。
实际参数被称为实参,是在调用方法时传递的参数;
形式参数被称为形参,是在方法定义中所写的参数。
② 引用参数和输出参数
方法中的参数除了定义数据类型外,还可以定义引用参数和输出参数。
引用参数使用 ref 关键字定义;
输出参数使用 out 关键字定义。
需要注意的两个点:
1)在调用带有引用参数的方法时,实际参数必须是一个变量,不能是变量或者表达式等等,并且在传值时必须加上 ref 关键字。
当是表达式的时候会报错:
当是常量的时候,也会出现报错
2) 使用输出参数时,必须在方法调用完成前为输出参数赋值
引用参数与我们平时使用的参数有些类似,但输出参数不同,输出参数相当于返回值,即在方法调用完成后可以将返回的结果存放到输出参数中。
输出参数多用于一个方法需要返回多个值的情况。
在使用输出参数时,必须在传递参数时使用 out 关键字,但不必给输出参数赋值;
在方法调用完成前为输出参数赋值。
演示代码
using System; using System.Collections.Generic; using System.Text; /* * 【实例 1】创建名为 RefClass 的类, * 在类中定义一个判断所输入整数是否为 5 的倍数的方法, * 并将方法中传入的整数参数定义为 ref 类型的。 */ namespace OOPDemo_1 { class RefClass { public bool Judge(ref int num) { if ((num % 5) == 0) return true; else return false; } } } /*******************************************************/ using System; using System.Collections.Generic; using System.Text; /* * 【实例 2】创建一个 OutClass 类,在类中定义与【实例 1】类似的方法, * 只是在方法的参 数中增加一个输出参数,用于返回判断的结果。 */ namespace OOPDemo_1 { class OutClass { public void Judge(int num,out bool result) { if (num % 5 == 0) result = true; else result = false; } } } /*******************************************************/ using System; namespace OOPDemo_1 { class Program { static void Main(string[] args) { RefClass refClass = new RefClass(); int a = 20; //int b = 23; //const int N = 5; //在调用带有引用参数的方法时,实际参数必须是一个变量,并且在传值时必须加上 ref 关键字。 bool res = refClass.Judge(ref a); Console.WriteLine("验证结果是:" + res); //调用含有带输出参数的方法时,必须在传递参数时使用 out 关键字,但不必给输出参数赋值 OutClass outClass = new OutClass(); bool rs; outClass.Judge(a, out rs); Console.WriteLine(rs); } } }
调用类成员
调用类的成员需要使用这个类的对象,对于创建类的对象。
创建类对象的语法形式如下:
类名 对象名 = new 类名();
上面的语法形式是一种简单形式,通过对象名结合.运算符即可调用类中的成员。
调用的语法形式如下:
对象名 . 类的成员
对于类的对象,我自己的理解是他是一个代理。
比如华为手机是一个类,Mate 40是创建的一个实例化对象,那么这个Mate 40就可以执行华为手机中的所有功能。
环节一 —— 创建对象以及调用方法
【随堂练习】在Book1类中添加一个方法,用于输出该类中的所有属性。
using System; using System.Collections.Generic; using System.Text; namespace OOPDemo_1 { class Book1 { public int Id { get; set; } public string Name { get; set; } public double Price { get; set; } public void PrintMsg() { Console.WriteLine("图书编号:" + Id); Console.WriteLine("图书名称:" + Name); Console.WriteLine("图书价格:" + Price); } } }
在项目的 Program.cs 文件里的 Main 方法中,加入调用 PrintMsg() 方法的代码。
class Program { static void Main(string[] args) { Book1 book1 = new Book1(); book1.PrintMsg(); } }
执行结果
环节二 —— 对属性赋值并输出
通过对象调用相应的属性,进行赋值:
class Program { static void Main(string[] args) { Book1 book1 = new Book1(); //为属性赋值 book1.Id = 520; book1.Name = "围城"; book1.Price = 131.4; book1.PrintMsg(); } }
【课堂练习】在 Book1 类中添加一个向属性赋值的方法,并在 Main 方法中调用。
class Book1 { public int Id { get; set; } public string Name { get; set; } public double Price { get; set; } public void SetBook(int id, string name, double price) { Id = id; Name = name; Price = price; } public void PrintMsg() { Console.WriteLine("图书编号:" + Id); Console.WriteLine("图书名称:" + Name); Console.WriteLine("图书价格:" + Price); } } /**********************主函数代码***********************************/ class Program { static void Main(string[] args) { Book1 book1 = new Book1(); book1.SetBook(520, "计围城", 131.4); book1.PrintMsg(); } }
如果要取得属性的值,直接使用类的对象.属性名即可;
如果给属性赋值的代码如下:
类的对象 . 属性名 = 值;
使用类的对象调用方法的代码:
类的对象 . 方法名(参数);
Tips:如果将类中的成员使用修饰符 static 声明,则在访问类成员时直接使用类名.类成员的方式即可。
【三】、知识积累——常用常见类
① Console 类 —— Console 类主要用于控制台应用程序的输入和输岀操作。
我现阶段认为重要的,常用的方法有这四个:
补充格式化输出
此外,在向控制台中输出内容时也可以对输出的内容进行格式化,格式化时使用的是占位符的方法,语法形式如下:
Console.Write(格式化字符串, 输出项1, 输出项2);
其中,在格式化字符串中使用{索引号}的形式,索引号从 0 开始。输出项 1 填充 {0} 位置的内容,依此类推。
现阶段,我认为比较值得掌握的属性有这三个:
至于其他更加详细的解说和总结,大家可以参考【微软C#官方文档——Console类】
② Math 类 —— Math 类主要用于一些与数学相关的计算,并提供了很多静态方法方便访问
Math类的常用方法还蛮多的,注意Max 和 Min 这两个超级常用
Tips:用的时候,一定要注意返回值类型,具体在使用之前,可以通过官方文档查阅
【Math 类官方文档】
③ Random 类 —— Random 类是一个产生伪随机数字的类
它的构造函数有两种: New Random(); New Random(Int32)。
前者是根据触发那刻的系统时间做为种子,来产生一个随机数字;
后者可以自己设定触发的种子,一般都是用 UnCheck((Int)DateTime.Now.Ticks) 做为参数种子。
Random中的常用方法:
想深入学习的,可以阅读一个官方文档了【Random 类 官方文档】
测试代码
class Program { static void Main(string[] args) { Random rd = new Random(); Console.WriteLine("产生一个10以内的数:{0}", rd.Next(0, 10)); Console.WriteLine("产生一个0到1之间的浮点数:{0}", rd.NextDouble()); byte[] b = new byte[5]; rd.NextBytes(b); Console.WriteLine("产生的byte类型的值为:"); foreach(byte i in b) { Console.Write(i + " "); } Console.WriteLine(); } }
④ DateTime 类 —— ateTime 类用于表示时间
这个我觉得蛮常用的,所表示的范围是从 0001 年 1 月 1 日 0 点到 9999 年 12 月 31 日 24 点。
一个重要的静态方法:
在 DateTime 类中提供了静态属性 Now,用于获取当前的日期和时间:
如下所示:
DateTime.Now
DateTime 结构 官方文档】
⑤ 嵌套类
核心知识
如果在其他类中调用嵌套类的成员,需要使用外部类.嵌套类的方式创建嵌套类的对象,从而通过嵌套类的对象调用其成员。
如果调用的是嵌套类中的静态成员,直接通过外部类 . 嵌套类 . 静态成员的方式调用即可。
嵌套类定义:
在类中除了能编写字段、属性、方法,还能直接定义类。将一个类定义在另一个类的内部,即可将在类内部定义的类称为嵌套类。
在 C# 中嵌套类相当于类中的成员,能使用类成员的访问修饰符和修饰符。但是,在访问嵌套类中的成员时必须加上外层类的名称。
测试代码
class OuterClass { //在OuterClaSS 类中 嵌套 InnerClass public class InnerClass { public string CardId { get; set; } public string Password { get; set; } public void PrintMsg() { Console.WriteLine("卡号为:" + CardId); Console.WriteLine("密码为:" + Password); } } } /***************************主函数代码****************************************/ class Program { static void Main(string[] args) { OuterClass.InnerClass outInner = new OuterClass.InnerClass(); outInner.CardId = "1314520"; outInner.Password = "123456"; outInner.PrintMsg(); Console.ReadKey(); } }
面向对象三大特征之一 —— 封装性
C# 封装根据具体的需要,设置使用者的访问权限,并通过 访问修饰符 来实现。
一个 访问修饰符 定义了一个类成员的范围和可见性。
public |
所有对象都可以访问 | |
private | 对象本身在对象内部可以访问 |
|
protected | 只有该类对象及其子类对象可以访问 | |
internal | 同一个程序集的对象可以访问 |
//
知道要用这四个访问修饰符来落实封装性就可以了,具体的深入展开要结合项目。
总结
对本篇文章而言,重要的是拿捏住以下四板知识内容:
① 区分清楚用于类的访问修饰符、修饰符以及用于类的成员的访问修饰符、修饰符
② 记清楚类中成员,以及如何构建对象,如何调用属性、方法,如何修改属性值
③ 积累常见类
④ 知道面向对象有三大特性,封装是如何实现的。