面向对象-封装
文章目录
- 1、类和对象
- 1、什么是类
- 2、类的声明
- 3、类声明语法
- 4、类声明实例
- 5、对象(类)
- 6、实例化对象语法
- 7、实例化对象
- 2、成员变量和访问修饰符
- 1、成员变量
- 2、访问修饰符
- 3、成员变量的使用和初始值
- 3、成员方法
- 1、成员方法声明
- 2、成员方法的使用
- 4、构造函数和析构函数
- 1、构造函数
- 2、构造函数特殊写法
- 3、析构函数
- 4、垃圾回收机制
- 5、成员属性
- 1、成员属性的基本概念
- 2、成员属性的基本语法
- 3、成员属性的使用
- 4、成员属性中 get 、set 前可以加访问修饰符
- 5、get和set可以只有一个
- 6、自动属性
- 6、索引器
- 1、索引器基本概念
- 2、索引器语法
- 3、索引器的使用
- 4、索引器可以写逻辑
- 5、索引器可以重载
- 思考 封装增删改查
- 7、静态成员
- 1、静态成员概念
- 2、遇见的静态成员
- 3、自定义静态成员
- 4、静态成员的使用
- 5、为什么可以直接使用
- 6、静态函数中不能使用非静态成员
- 7、非静态函数可以使用静态成员
- 8、静态成员对于我们的作用
- 9、常量和静态常量
- 思考 单例模式思想
- 8、静态类和静态构造函数
- 1、静态类
- 2、静态构造函数
- 思考 写一个静态的工具类
- 9、拓展方法
- 1、拓展方法的基本概念
- 2、基本语法
- 3、示例
- 4、为自定义的类型拓展方法
- 10、运算符重载
- 1、基本概念
- 2、基本语法
- 3、示例
- 4、可重载和不可重载的运算符
- 思考 重载运算符实现Vector3类(x,y,z)
- 11、内部类和分部类
1、类和对象
1、什么是类
具有相同特征、相同行为的一类事物的抽象
类是对象的模板
可以通过类创建出对象
2、类的声明
在namespace中
3、类声明语法
class 类名{特征-成员变量行为-成员方法保护特征-成员属性构造函数和析构函数索引器运算符重载静态成员
}
4、类声明实例
class Person{}
5、对象(类)
对象是类创建的
类创建的过程称为实例化对象类是引用类型,结构体是值类型
6、实例化对象语法
类名 变量名;
类名 变量名 = null;
类名 变量名 = new 类名();
7、实例化对象
Person p; Person P2 = null; //没有分配堆内存
Person p3 = new Person(); //分配了堆内存
Person p4 = new Person(); //p3和p4没有关系
2、成员变量和访问修饰符
1、成员变量
1、声明在类语句块中
2、用来描述对象的特征
3、可以是任意变量类型
4、数量不做限制
5、是否赋值根据需求来定
enmu E_SexType{Man,Woman,}
struct Position{}
class Pet{}
class Person{//特征-成员变量public string name;public int age;public E_SexType sex;public Person girlFriend; //类可以声明和自己一样的变量类型,这样的成员变量不能实例化public Person[] friend;public Position pos;public Pet pet;
}
2、访问修饰符
public 共有的 外部访问
private 内部访问,默认
protected 内部和子类访问
3、成员变量的使用和初始值
值类型: 数字默认值为0 bool类型 false
引用类型: null
Console.WriteLine(default(int));
3、成员方法
1、成员方法声明
概念成员方法用来表现对象行为1、声明在类语句块中2、是用来描述对象的行为3、规则和函数声明规则相同4、收到访问修饰符规则影响5、返回值参数不做限制6、方法数量不做限制class Person{public string name;public int age;public Person[] friends;//添加新朋友的方法public void AddFriend(Person p){if(friends == null){friends = new Person[] {p};}else{//新建一个数组Person[] newFriends = new Person[friends.Length + 1];for(int i = 0;i < friends.Length; i++){newFriends[i] = friends[i];}//添加新朋友newFfriends[newFriends.Length - 1] = p;//地址重定向friends = newFriends;}}public void Speak(string str){Console.WriteLine("{0}说{1}",name,str);}public bool IsAdult(){return age >= 18;}}
2、成员方法的使用
Person p = new Person();
p.name = "魔君";
p.age = 18;
p.Speak("什么");if(p.IsAdult){p.Speak("成年了");
}//添加新朋友
Person p2 = new Person();
p2.name = "大舅哥";
p2.age = 20;
p.AddFriend(p2);
for(int i =0;i<p.friends.Length; i++){Console.WriteLine(p.friends[i].name);
}
4、构造函数和析构函数
1、构造函数
概念在实列化对象时,会调用用于初始化的函数若不写,默认存在一个无参构造函数构造函数的写法1、没有返回值2、函数名必须和类名相同3、构造函数可以重载4、this代表当前调用该函数的对象class Person{public string name;public int age;//类中可以声明无参构造函数,结构体不可以public Person(){name = "魔君";age = 18;}//有参构造会顶替掉默认的无参构造public Person(int age, string name){this.age = age; //this代表当前成员变量this.name = name;}
}
Person p = new Person(18,"魔君");
Console.WriteLine(p.age);
2、构造函数特殊写法
可以通过this 重用构造函数代码
访问修饰符 构造函数名(参数列表):this(参数1,参数2...)
public Person(){}public Person(int age, string name):this(){ //先调用无参方法,复用代码Console.WriteLine("Person两个参数构造函数调用");
}public Person():this("魔君"){Console.WriteLine("Person两个参数构造函数调用");
}public Person(int age, string name):this(age + 10){Console.WriteLine("Person两个参数构造函数调用");
}
3、析构函数
概念当引用类型的堆内存被回收时,会调用该函数
基本语法~类名(){}~Person(){}
4、垃圾回收机制
垃圾回收,GC(Garbage Collector)
垃圾回收过程时在遍历堆(Heap)上动态分配的所有对象
垃圾就是没有被任何变量,对象引用的内容垃圾回收算法引用计数(Reference Counting)标记清楚(Mark Sweep)标记整理(Mark Compact)复制集合(Copy Collection)GC只负责堆(Heap)内存的垃圾回收,引用类型通过GC回收
栈(Stack)上的内存是由系统自动管理的,值类型会随生命周期自动释放C#中GC大概原理
0代内存 1代内存 2代内存
代是垃圾回收机制使用的一种算法(分代算法)
新分配的对象都会被配置在第0代内存中
每次分配都可能会进行垃圾回收以释放内存(0代内存满时)在一次内存回收过程开始时,垃圾回收器会认为堆中全是垃圾:1、标记对象 从根(静态字段、方法参数)开始检查引用对象,标记后为可达对象,未标记为不可达对象2、搬迁对象压缩堆(挂起执行托管代码线程),释放未标记的对象,搬迁可达对象,修改引用地址大对象认为是第二代内存,目的是减少性能损耗,提高性能
不会对大对象进行搬迁压缩 85000字节(83kb)以上为大对象//手动GC方法,用于Loading过场景时调用GC.Collect();
5、成员属性
1、成员属性的基本概念
1、用于保护成员变量
2、为成员属性的获取和赋值添加逻辑处理
3.解决访问修饰符的局限性
2、成员属性的基本语法
访问修饰符 属性类型 属性名{get{}set{}}class Person{private string name;private int age;private int money;private bool sex;public string Name{get{return name; //返回通过属性获取的内容}set{//value 关键字用于表示外部传入的值name = value;}}
}
3、成员属性的使用
Person p = new Person();
p.Name = "老哥";
Console.WriteLine(p.Name);
4、成员属性中 get 、set 前可以加访问修饰符
1、不加修饰符 默认为属性声明时的访问权限
2、加的访问修饰符要低于属性的访问权限
3、不能让get和set的访问权限都低于属性的权限
public int Money{get{//解密处理return money - 5;}set{//加密处理money = value + 5;}
}
5、get和set可以只有一个
只有一个时,不加访问修饰符
6、自动属性
作用:外部能得不能改的特征如果类中有一个特征是只希望外部能得到但不能修改,没有什么特殊处理的情况,可以直接使用自动属性
public float Height{get;private set;
}
6、索引器
1、索引器基本概念
让对象可以像数组一样通过索引访问其中元素,使程序更直观,更容易编写
2、索引器语法
访问修饰符 返回值 this[参数类型 参数名, 参数类型 参数名]
{内部写法和规则和属性相同get{}set{}
}class Person{private string name;private int age;private Person[] friends;public Person this[int index]{get{return fridents[index];}set{friends[index] = value;}}
}
3、索引器的使用
Person p = new Person();
p[0] = new Person();
Console.WriteLine(p[0]);
4、索引器可以写逻辑
class Person{private string name;private int age;private Person[] friends;public Person this[int index]{get{if(fridens == null || friends.Length - 1 < index){return null;}return fridents[index];}set{if(friends == null){friends = new Person[] {value};}else if(index > friends.Length - 1){friends[friends.Length - 1] = value;}friends[index] = value;}}
}
5、索引器可以重载
p[0,0] = 10;class Person{private string name;private int age;private Person[] friends;private int[,] array;public int this[int i, int j]{get{return array[i,j];}set{array[i,j] = value;}}public string this[string str]{get{switch(str){case "name":return this.name;case "age":return age.ToString();}return "";}}public Person this[int index]{get{}set{}}
}
思考 封装增删改查
//定义一个整型数组类,该类中有一个整型数组变量,为它封装增删改查方法IntArray array = new IntArray();
array.Add(10);
array.Add(20);
array.Add(30);
array.Add(40);
array.Add(50);
//array.RemoveAt(1);
array.Remove(2);
Console.WriteLine(array[3]);
Console.WriteLine(array.Length);
class IntArray
{private int[] array;//房间容量private int capacity;//当前房间数private int length;public IntArray(){capacity = 5;length = 0;array = new int[capacity];}//增public void Add(int value){//是否扩容if(length < capacity){array[length] = value;length++;}else // 扩容,换新数组{capacity *= 2;//新房间int[] tempArray =new int[capacity];//旧换新for (int i = 0; i < array.Length; i++){tempArray[i] = array[i];}array = tempArray; //老房子地址指向新房子地址//添加内容array[length] = value;length++;}}//删public void Remove(int value) {for (int i = 0; length > i; i++){if (array[i] == value){RemoveAt(i);return;}}Console.WriteLine("没有在数组中找到{0}",value);}public void RemoveAt(int index){if (index > length - 1){Console.WriteLine("当前数组长度只有{0}", length);return;}for (int i = index; i < length - 1; i++){array[i] = array[i + 1]; //前移数组元素}length--;}//改查public int this[int index]{get{if(index>=length || index < 0){Console.WriteLine("越界");return 0;}return array[index];}set{if (index >= length || index < 0){Console.WriteLine("越界");}array[index] = value;}}public int Length{get{return length;}}
}
7、静态成员
1、静态成员概念
静态关键字 static
用static修饰的 成员变量、方法、属性等,称为静态成员
静态成员的特点:直接用类名.静态成员使用
2、遇见的静态成员
Console是静态成员
3、自定义静态成员
class Test{//静态成员变量public static float PI = 3.14f;//成员变量public int testInt = 100;//静态成员方法public static float CalCircle(float r){return PI * r * r;}//成员方法public void TestTun(){Console.WriteLine("123");}
}
4、静态成员的使用
Console.WriteLine(Test.PI);
Console.WriteLine(Test.CalCircle(2));
5、为什么可以直接使用
静态成员的特点程序开始运行时,就会分配内存空间。所以静态成员和程序同生共死,静态成员具有唯一性和全局性
6、静态函数中不能使用非静态成员
成员变量只能将对象实例化后才能使用,不能直接使用 非静态成员
7、非静态函数可以使用静态成员
静态生命周期长
8、静态成员对于我们的作用
静态变量:1、常用唯一变量的声明2、方便别人获取对象声明
静态方法:常用唯一的方法声明
9、常量和静态常量
const 可以理解为特殊的static
相同点:都可以不通过实例化直接使用
不同点:1、const必须初始化,不能修改; static没有此规则2、const只能修饰变量; static可以修饰其他3、const一定写在访问修饰符后; static可以写前面
思考 单例模式思想
//一个类对象,在整个应用程序的生命周期中,有且仅有一个该对象存在
//不能在外部实例化,直接通过该类类名就能够得到唯一的对象Console.WriteLine(Test.T.testInt);class Test
{private static Test t = new Test();public int testInt = 10;public static Test T{get{return t;}}private Test() {}
}
8、静态类和静态构造函数
1、静态类
概念用static修饰的类
特点只能包含静态成员,不能被实例化
作用1、将常用的静态成员写在静态类中,方便使用2、静态类不能被实例化,更能体现工具类的唯一性
2、静态构造函数
概念在构造函数上加static修饰
特点1、静态类和普通类都可以2、不能使用访问修饰符3、不能有参数4、只会调用一次
作用在静态构造函数中初始化 静态变量
使用1、静态类中的静态构造函数2、普通类中的静态构造函数
思考 写一个静态的工具类
//写一个用于数学计算的静态类
//该类中提供计算圆面积,周长,矩形面积,矩形周长,取一个数的绝对值Console.WriteLine(MathTool.CalcCircularArea(2));
Console.WriteLine(MathTool.CalcCircularLength(2));
Console.WriteLine(MathTool.CalcRectArea(2,3));
Console.WriteLine(MathTool.CalcRectLength(2,3));
Console.WriteLine(MathTool.GetABS(-22));static class MathTool
{public static float PI = 3.14f;/// <summary>/// 计算圆面积/// </summary>/// <param name="r">半径</param>/// <returns>周长</returns>public static float CalcCircularArea(float r){return PI * r * r;}public static float CalcCircularLength(float r){return 2 * PI * r;}public static float CalcRectArea(float w,float h){return w * h;}public static float CalcRectLength(float w, float h){return 2 * (w + h);}public static float GetABS(float value){if (value < 0){return -value;}return value;}
}
9、拓展方法
1、拓展方法的基本概念
概念为现有非静态变量类型添加新方法
作用1、提升程序拓展性2、不需要再对象中重新写方法3、不需要继承来添加方法4、为别人封装的类型写额外的方法
特点1、一定是写在静态类中2、一定是一个静态函数3、第一个参数为拓展目标4、第一个参数用this修饰
2、基本语法
访问修饰符 static 返回值(this 拓展类名 参数名,参数类型 参数名)
3、示例
int i = 10;
i.SperkValue();static class Tools{//为int拓展了一个成员方法//成员方法是需要实例化对象后才能使用//value代表使用该方法的实例化对象public static void SpeakValue(this int value){//拓展方法的逻辑Console.WriteLine("为int拓展的方法"+value);}
}
4、为自定义的类型拓展方法
Test t = new Test();
t.Fun3();
static class Tools{public static void Fun3(this Test t){Console.WriteLine("为Test写的拓展方法");}
}
class Test{public int i = 20;public void Fun1(){Console.WriteLine("123");}public void Fun2(){Console.WriteLine("456");}
}
10、运算符重载
1、基本概念
概念让自定义类和结构体能够使用运算符
关键字operator
特点1、一定是一个公共的静态方法2、返回值写在operator前3、逻辑处理自定义
作用让自定义类和结构体对象可以进行运算
注意1、条件运算符需要成对实现2、一个符号可以多个重载,注意参数3、不能使用ref 和 out
2、基本语法
public static 返回类型 operator 运算符(参数列表)
3、示例
Point p = new Point();
p.x = 1;
p.y = 1;
Point p2 = new Point();
p2.x = 2;
p2.y = 2;
Point p3 = p + p2;Point p4 = p3 + 2;class Point{public int x;public int y;public static Point operator +(Point p1, Point p2){Point p = new Point();p.x = p1.x + p2.x;p.y = p1.y + p2.y;return p;}public static Point operator +(Point p1, int value){Point p = new Point();p.x = p1.x + value;p.y = p1.y + value;return p;}
}
4、可重载和不可重载的运算符
1、可重载的运算符算数运算符 //都可以public static Point operator -(Point p1, Point p2){return null};public static Point operator *(Point p1, Point p2){return null};public static Point operator /(Point p1, Point p2){return null};public static Point operator %(Point p1, Point p2){return null};public static Point operator ++(Point p1){return null};public static Point operator --(Point p1){return null};逻辑运算符 //逻辑非可以!public static bool operator !(Point p1){return false};位运算符 //都可以public static Point operator |(Point p1, Point p2){return null};public static Point operator &(Point p1, Point p2){return null};public static Point operator ^(Point p1, Point p2){return null};public static Point operator ~(Point p1){return null};public static Point operator <<(Point p1, Point p2){return null};public static Point operator >>(Point p1, Point p2){return null};条件运算符 //成对出现public static bool operator >(Point p1, Point p2){return false};public static bool operator <(Point p1, Point p2){return false};public static bool operator >=(Point p1, Point p2){return false};public static bool operator <=(Point p1, Point p2){return false};public static bool operator ==(Point p1, Point p2){return false};public static bool operator !=(Point p1, Point p2){return false};
2、不可重载的运算符逻辑与&& 逻辑或||索引符[]强转运算符()特殊运算符三目运算符 赋值符号= 点.
思考 重载运算符实现Vector3类(x,y,z)
//定义一个Vector3类(x,y,z)通过重载运算符实现以下运算
//(x1, y1, z1) + (x2, y2, z2) = (x1 + x2, y1 + y2, z1 + z2)
//(x1, y1, z1) - (x2, y2, z2) = (x1 - x2, y1 - y2, z1 - z2)
//(x1, y1, z1) * num = (x1 * num, y1 * num, z1 * num)Vector3 v1 = new Vector3(1,1,1);
Vector3 v2 = new Vector3(2,2,2);Vector3 v3 = v1 + v2;
Console.WriteLine("Vector3({0},{1},{2})", v3.x,v3.y,v3.z);Vector3 v4 = v1 - v2;
Console.WriteLine("Vector3({0},{1},{2})", v4.x, v4.y, v4.z);v4 *= 3;
Console.WriteLine("Vector3({0},{1},{2})", v4.x, v4.y, v4.z);class Vector3
{public int x; public int y; public int z;public Vector3(int x, int y, int z){this.x = x;this.y = y;this.z = z;}public static Vector3 operator +(Vector3 v1, Vector3 v2){return new Vector3(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);}public static Vector3 operator -(Vector3 v1, Vector3 v2){return new Vector3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);}public static Vector3 operator *(Vector3 v,int num){return new Vector3(v.x * num, v.y * num, v.z * num);}
}
11、内部类和分部类
1、内部类
概念在类中再声明一个类
特点使用时要用包括者点出自己
作用亲密关系的体现
注意访问修饰符作用很大
2、分部类
概念把一个类分成几部分声明
关键字partial
作用分部表述一个类增加程序的拓展性
注意分部类可以写在多个脚本文件中分部类的访问修饰符要一致分部类中不能有重复成员
3、分部方法
概念将方法的声明和实现分离
特点1、不能加访问修饰符,默认私有2、只能在分部类中声明3、返回值只能是void4、可以有参数但不用out关键字