ToB企服应用市场:ToB评测及商务社交产业平台

标题: C#学习笔记--面向对象三大特征 [打印本页]

作者: 罪恶克星    时间: 2023-10-29 00:29
标题: C#学习笔记--面向对象三大特征
C#核心

面向对象--封装

用程序来抽象现实世界,(万物皆对象)来编程实现功能。
三大特性:封装、继承、多态。
类与对象

声明位置:namespace中
样式:class 类名{}
命名:帕斯卡命名法(首字母大写)
实例化对象:根据类来新建一个对象。Person p=new Person();
成员变量

  1. enum E_SexType
  2. {
  3.     Man,
  4.     Woman
  5. }
  6. struct Position{}//位置结构体
  7. class Pet{}//宠物类
  8. //类中的成员变量
  9. class Person
  10. {
  11.     public string name="TonyChang";//区别于结构体--可以默认赋初始值
  12.     public int age=21;
  13.     public E_SexType sex;
  14.     public Person bestFriend;//区别于结构体---类中可以有同类的成员类型(本质是因为类属于引用类型,但不可以实例化,防止反复new,陷入死循环)
  15.     public Position pos;
  16.     public Pet pet;
  17. }
复制代码
成员类型的默认值:
值类型的:数字的为0,bool类型的false
引用类型:null
查看(int类型)默认值:default(int)
补充:class属于引用类型,其中的值类型也放置在中。
成员方法

成员方法只有在实例化之后才可以使用调用。具体的一个对象的行为(方法),必须具体的对象调用。
  1. //成员方法
  2. class Person
  3. {
  4.     public string name;
  5.     public int age;
  6.     public void Speak()
  7.     {
  8.         Console.WriteLine("你好!");
  9.     }   
  10. }
  11. //成员方法的使用
  12. Person p=new Person;
  13. p.Speak();
复制代码
构造函数和析构函数

默认有一个无参构造函数,而类中可以允许自己声明无参构造函数,而结构体不行。
一旦有自定义的构造函数,默认的无参构造函数则失效!
构造函数:
  1. class Person
  2. {
  3.     public string name;
  4.     public int age;
  5.     //构造函数
  6.     public Person()
  7.     {
  8.         name="TonyChang";
  9.         age=21;
  10.     }
  11.     //此时先调用age参数的构造函数 然后再调用两个参数的构造函数
  12.     public Person(string name,int age):this(age)
  13.     {
  14.         this.name=name;
  15.         this.age=age;
  16.     }
  17.     public Person(string name)
  18.     {
  19.        this.name=name;
  20.     }
  21.     public Person(int age)
  22.     {
  23.         this.age=age;
  24.     }
  25. }
复制代码
特殊的构造函数,在调用该函数之前先调用this的无参构造函数。
public Person(int age):this()
{
this.age=age;
}
析构函数:
由于C#中有自动的垃圾回收机制,一般不使用析构函数。
析构函数是当垃圾真正被回收时候才会调用。
~Person(){}//析构函数
成员属性:

用于保护成员变量,为成员属性的获取和赋值添加逻辑处理。
  1. //成员属性 帕斯卡命名法
  2. class Person
  3. {
  4.     private string name;
  5.     public string Name
  6.     {
  7.         get{
  8.             return name;
  9.         }
  10.         set{
  11.             name=value;
  12.         }
  13.     }
  14.     private int age;
  15.     public int Age
  16.     {
  17.         //不可以获得年龄(或者删除set设置则可表明也无法获取age)
  18.         private get=>age;
  19.         //可以设置年龄
  20.         set
  21.         {
  22.             age=value;
  23.         }
  24.     }
  25.     //额外:
  26.     //自动成员属性 (对于没有特殊需要的成员)
  27.     public float Height
  28.     {
  29.         get;
  30.         set;
  31.     }
  32. }
复制代码
索引器

可以让对象像数组一样通过索引来访问其中的元素。
注意:结构体中也支持索引器。
  1. //索引器
  2. class Person
  3. {
  4.     private string name;
  5.     private int age;
  6.     private Person[] friends;
  7.     private int[,] arry;
  8.     //索引器
  9.     public Person this[int index]
  10.     {
  11.         get
  12.         {
  13.             return friends[index];
  14.         }
  15.         set
  16.         {
  17.             //此处可以写一些控制逻辑
  18.             friends[index]=value;
  19.         }
  20.     }
  21.     //索引器的重载
  22.     public int this[int i,int j]
  23.     {
  24.         get
  25.         {
  26.             return array[i,j];
  27.         }
  28.         set
  29.         {
  30.             array[i,j]=value;
  31.         }
  32.     }
  33. }
  34. //使用
  35. Person p=new Person();
  36. p[0]=new Person();//可以像数组一样进行访问
复制代码
静态成员

static修饰的成员变量/方法为静态成员。
静态成员归属为类,即不用初始化就可以使用的类的成员。
静态成员函数中不可以使用非静态成员,非静态成员函数中可以使用静态成员函数。
本质:在程序运行开始时,检查到静态成员,会再特定的区域为其开辟内存空间来存储。所以说静态成员与程序共生死。因为生命周期不同,所以静态成员函数中不可以使用非静态成员。
使用:全局性,稳定不变的常量。例如固定的数值 Π,重力加速度g等包括固定的计算方法,可以供全局成员来访问使用。但是静态过多会占用内存,引发GC。
常量与静态成员

相同点:都可以通过类名点来使用
不同点:
静态类与静态构造函数

用 static修饰的类为静态类,往往来作为工具类。例如System中的Console类。只能包含静态成员,不能实例化。
静态构造函数 :在静态构造函数中初始化静态成员变量。
  1. //静态构造函数
  2. static class Test
  3. {
  4.     public static int testInt=100;
  5.     public static float testFloat=20.5f;
  6.     static Test()
  7.     {
  8.         //静态构造函数
  9.         Console.WriteLine("自动调用了!");
  10.     }
  11. }
  12. class NormalTest
  13. {
  14.     public static int i=5;
  15.     //首次使用静态成员时候 自动调用一次
  16.     //静态成员函数
  17.     static NormalTest()
  18.     {
  19.         Console.WriteLine("静态构造函数");
  20.     }
  21.     public NormalTest()
  22.     {
  23.         Console.WriteLine("非静态成员函数");
  24.     }
  25. }
复制代码
拓展方法

拓展方法为现有的非静态变量类型添加新方法。
作用:
特点:
  1. //拓展方法
  2. static class expendTool
  3. {
  4.     //为int添加拓展方法
  5.     public static void SpeakValue(this int value)
  6.     {
  7.         Console.WriteLine("这是int的拓展方法,int的数值为{0}",value);
  8.     }
  9.     //为string拓展方法
  10.     public static void SpeakStringInfo(this string str,string name,string info)
  11.     {
  12.          Console.WriteLine("这是string的拓展方法,string的数值为{0},该拓展方法由{1}编写,拓展内容为{2}",str,name,info);
  13.     }
  14. }
  15. class Program
  16. {
  17.     static void Main(string[] args)
  18.     {
  19.         int i = 5;
  20.         i.SpeakValue();
  21.         string ss = "原始字符串";
  22.         ss.SpeakStringInfo("TonyChang", "附加字符串");
  23.     }
  24. }
复制代码
注意:如果拓展方法名称与自身现有的方法名称相同,则只会调用自身的方法,不会调用拓展的方法。
运算符重载

关键字 operator
特点:1.  一定是一个公共的静态成员方法
作用:可以使自定义的数据类型来完成后相同意义的运算。
注意:
手动GC:
GC.Collect();
一般在场景加载时候进行GC。
面向对象--继承

继承者(子类)继承父类(基类、超类)的特性,同时也可以有自己独特的方法性质。
只能单继承。子类只能由一个父类。
继承特性:单根性、传递性。
  1. //运算符重载
  2. class Point
  3. {
  4.     public int x;
  5.     public int y;
  6.     public Point(int x,int y)
  7.     {
  8.         this.x=x;
  9.         this.y=y;
  10.     }
  11.    
  12.     //重载+运算符
  13.     //参数列表中必须要有自己的类别出现
  14.     public static Point operator +(Point p1,Point p2)
  15.     {
  16.         Point sum=new Point();
  17.         sum.x=p1.x+p2.x;
  18.         sum.y=p1.y+p2.y;
  19.         return sum;
  20.     }
  21. }
  22. class Program
  23. {
  24.     static void Main(string[] args)
  25.     {
  26.         Point p1=new Point(1,1);
  27.         Point p2=new Point(2,2);
  28.         Point p3=P1+p2;
  29.         Console.WriteLine(p3.x);
  30.     }
  31. }
复制代码
里氏替换原则

父类容器装在子类对象。(任何父类出现的地方,子类都可以替代)
  1. //内部类
  2. class Person
  3. {
  4.     public class Body
  5.     {
  6.         class Arm
  7.         {
  8.             
  9.         }
  10.     }
  11. }
  12. class Program
  13. {
  14.     static void Main(string[] args)
  15.     {
  16.        Person.Body body=new Person.Body();
  17.     }
  18. }
  19. //分布类
  20. //分布类可以分布在不同的脚本文件中
  21. //分布类的访问修饰符要一致
  22. partial class Student
  23. {
  24.     public string name;
  25.     public bool sex;
  26.     partial void Speak();
  27. }
  28. partial class Student
  29. {
  30.     public int age;
  31.     public string stuId;
  32.     partial void Speak()
  33.     {
  34.         Console.WriteLine("分布方法的具体实现");
  35.     }
  36. }
复制代码
is和as

is是判断一个对象是否为指定类型对象,返回值为true则为真,不是则为false
as用来将一个对象转换为指定类型对象,返回值为指定类型对象,若转换失败则返回null
继承中的构造函数

子类构造函数调用之前,先执行父类的构造函数。(爷爷-->父亲-->子类)
所以要保证父类的构造函数(尤其为无参构造函数)
  1. //继承
  2. //老师类
  3. class Teacher
  4. {
  5.     //姓名
  6.     public string name;
  7.     //职工号
  8.     protected int number;
  9.     //介绍名字
  10.     public void SpeakName()
  11.     {
  12.         number = 10;
  13.         Console.WriteLine(name);
  14.     }
  15. }
  16. //教学老师继承老师类
  17. class TeachingTeacher : Teacher
  18. {
  19.     //科目
  20.     public string subject;
  21.     //介绍科目
  22.     public void SpeakSubject()
  23.     {
  24.         number = 11;
  25.         Console.WriteLine(subject + "老师");
  26.     }
  27. }
  28. //语文老师继承教学老师类
  29. class ChineseTeacher:TeachingTeacher
  30. {
  31.     public void Skill()
  32.     {
  33.         Console.WriteLine("一行白鹭上青天");
  34.     }
  35. }
  36. class Program
  37. {
  38.     static void Main(string[] args)
  39.     {
  40.         TeachingTeacher tt = new TeachingTeacher();
  41.         tt.name = "汪老师";
  42.         //tt.number = 1;
  43.         tt.SpeakName();
  44.         tt.subject = "Unity";
  45.         tt.SpeakSubject();
  46.         ChineseTeacher ct = new ChineseTeacher();
  47.         ct.name = "张老师";
  48.         //ct.number = 2;
  49.         ct.subject = "语文";
  50.         ct.SpeakName();
  51.         ct.SpeakSubject();
  52.         ct.Skill();
  53.     }
  54. }
复制代码
万物之父--装箱和拆箱

object 是所有类型的基类,
作用:
装箱:
用object存值类型。本该在栈中数值转移到堆上
拆箱
将object转换为值类型,将堆上的值类型转移到栈上(配合 is和as 使用)
优点:统一对象类型(里氏替换原则),方便对不同类型对象数值的管理
缺点:消耗性能,
  1. class GameObject
  2. {
  3. }
  4. class Player:GameObject
  5. {
  6.     public void PlayerAtk()
  7.     {
  8.         Console.WriteLine("玩家攻击");
  9.     }
  10. }
  11. class Monster:GameObject
  12. {
  13.     public void MonsterAtk()
  14.     {
  15.         Console.WriteLine("怪物攻击");
  16.     }
  17. }
  18. class Boss:GameObject
  19. {
  20.     public void BossAtk()
  21.     {
  22.         Console.WriteLine("Boss攻击");
  23.     }
  24. }
  25. class Program
  26. {
  27.     static void Main(string[] args)
  28.     {
  29.         //里氏替换原则
  30.         Gameobjet player=new Player();
  31.         Gameobjet monster=new Monster();
  32.         Gameobjet boss=new Boss();
  33.         //is 和 as
  34.         if(player is Player)
  35.         {
  36.             (player as Player).PlayerAtk();
  37.         }
  38.     }
  39. }
复制代码
*密封类(了解)

使用sealed关键字修饰的类,不可以被派生。(结扎了!)
面向对象--多态

V: virtual(虚函数)
O: override(重写)
B: base(父类)
让继承同一父类的子类们在执行相同方法有不同的表现与状态。
就是说,继承是一脉相承父类的品质,而多态是由自己的个性,尽管做的和父辈的事情相同。
解决的问题:
  1. //继承中的构造函数
  2. class Father
  3. {
  4.     //父类的无参构造函数很重要!
  5.     public Father()
  6.     {
  7.         
  8.     }
  9.     public Father(int i)
  10.     {
  11.         Console.WriteLine("Father的有参构造");
  12.     }
  13. }
  14. class Son:Father
  15. {
  16.     public Son(int i):base(i)
  17.     {
  18.         //构造函数
  19.     }
  20. }
复制代码
使用多态来保证(继承类)一个类方法的独立性
  1. //装箱拆箱
  2. int i=5;
  3. object obj=i;//装箱
  4. i=(int)obj;//拆箱
复制代码
抽象类与抽象方法

抽象类不可以被实例化
abstract class Thing{
public string name;
}
抽象方法:没有方法体的纯虚方法,继承的子类必须实现纯虚方法。(子类必须重写该方法,子类的子类不必强制实行,但也可以继续重写。)
抽象方法与virtual(虚函数)方法区别:
  1. class Father
  2. {
  3.     public void SpeakName()
  4.     {
  5.         Console.WriteLine("Father的方法");
  6.     }
  7. }
  8. class Son:Father
  9. {
  10.     public new void SpeakName()
  11.     {
  12.         Console.WriteLine("Son的方法");
  13.     }
  14. }
  15. class Program
  16. {
  17.     static void Main(string[] args)
  18.     {
  19.         #region 解决的问题
  20.         Father f = new Son();
  21.         f.SpeakName();//调用的是父亲的方法
  22.         (f as Son).SpeakName();//调用的是儿子的方法
  23.         #endregion
  24.     }
  25. }
复制代码
接口(重要)

概念:接口是行为的抽象规范
关键字:interface
声明规范:
使用规范:
特点:
接口是抽象行为的”基类“
  1. class GameObject
  2. {
  3.     public string name;
  4.     public GameObject(string name)
  5.     {
  6.         this.name = name;
  7.     }
  8.     //虚函数 可以被子类重写
  9.     public virtual void Atk()
  10.     {
  11.         Console.WriteLine("游戏对象进行攻击");
  12.     }
  13. }
  14. class Player:GameObject
  15. {
  16.     public Player(string name):base(name)
  17.     {
  18.     }
  19.     //重写虚函数
  20.     public override void Atk()
  21.     {
  22.         //base的作用
  23.         //代表父类 可以通过base来保留父类的行为
  24.         base.Atk();
  25.         Console.WriteLine("玩家对象进行攻击");
  26.     }
  27. }
复制代码
接口的使用---类的继承
  1. abstract class Fruits
  2. {
  3.     public string name;
  4.     //抽象方法 是一定不能有函数体的
  5.     public abstract void Bad();
  6.     public virtual void Test()
  7.     {
  8.         //可以选择是否写逻辑
  9.     }
  10. }
  11. class Apple : Fruits
  12. {
  13.     public override void Bad()
  14.     {
  15.     }
  16.     //虚方法是可以由我们子类选择性来实现的
  17.     //抽象方法必须要实现
  18. }
复制代码
接口的使用---接口的继承
接口继承基类接口之后,不需要实现接口中的内容(抽象继承抽象,还是抽象)
等到最后类来具体实现
  1. //接口的声明
  2. //命名规范 I+帕斯卡命名法
  3. interface IFly
  4. {
  5.     void Fly();//方法
  6.     string Name//属性
  7.     {
  8.         get;
  9.         set;
  10.     }
  11.     int this[int index]//索引器
  12.     {
  13.         get;
  14.         set;
  15.     }
  16.     event Action doSomthing;//事件委托
  17. }
复制代码
显示实现接口
  1. //接口的使用
  2. class Animal
  3. {
  4.    
  5. }
  6. class Person:Animal,IFly
  7. {
  8.     //实现接口方法也可以加virtual来实现
  9.     public virtual void Fly()
  10.     {
  11.         
  12.     }
  13.     public string Name
  14.     {
  15.         set;
  16.         get;
  17.     }
  18.     public int this[int index]
  19.     {
  20.         get
  21.         {
  22.             return 0;
  23.         }
  24.         set
  25.         {
  26.             
  27.         }
  28.     }
  29.     public event Action doSomething;
  30. }
复制代码
*密封方法(了解)
sealed 修饰的重写方法,子类不会被重写方法
其它关联知识点

命名空间namespace

万物之父Object中的方法

string

StringBuilder

字符串频繁拼接使用StringBuilder,不会再次频繁的创建新的对象,减少垃圾产生。
容量问题:初始时候本身有一定容量,在容量允许范围内,直接存储。
超过容量之后,会以2倍大小扩容。相对于string每一次更改便会新建对象,可减少垃圾产生。
  1. //接口继承接口
  2. interface IWalk
  3. {
  4.     void Walk();
  5. }
  6. interface IMove:IFly,IMove
  7. {
  8.    
  9. }
  10. //必须实现所有相关的
  11. //继承来的抽象内容(接口,接口的父接口中的成员)
  12. class Test:IMove
  13. {
  14.    
  15.        public int this[int index] {
  16.            get => throw new NotImplementedException();
  17.            set => throw new NotImplementedException();
  18.        }
  19.         public string Name {
  20.             get => throw new NotImplementedException();
  21.             set => throw new NotImplementedException();
  22.         }
  23.         public event Action doSomthing;
  24.         public void Fly()
  25.         {
  26.             throw new NotImplementedException();
  27.         }
  28.         public void Walk()
  29.         {
  30.             throw new NotImplementedException();
  31.         }
  32. }
复制代码
String 还是StringBuilder?
String的方法种类较多,使用更加方便和灵活,但性能上不如StringBuilder,不如StringBuilder产生垃圾少
需要频繁修改的字符串选用StringBuilder更好些。
如何优化内存?
结构体与类的区别

如何选择结构体和类:
抽象类与接口的区别

相同点:
区别:
如何选择抽象类与接口
表示对象的选用抽象类,表示行为拓展的用接口。不同对象的相同行为,我们可以抽象出行为,用接口来实现。
面向对象的七大原则

总目标:高内聚、低耦合
减少类内部对其它类的调用,减少模块与模块之间的交互复杂度。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4