C#核心之面向对象-封装

发布于:2024-05-06 ⋅ 阅读:(147) ⋅ 点赞:(0)

面向对象-封装
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

文章目录

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、静态成员概念
静态关键字 staticstatic修饰的 成员变量、方法、属性等,称为静态成员
静态成员的特点:直接用类名.静态成员使用
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
相同点:
    都可以不通过实例化直接使用
不同点:
    1const必须初始化,不能修改; static没有此规则
    2const只能修饰变量; static可以修饰其他
    3const一定写在访问修饰符后; 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、返回值只能是void
    4、可以有参数但不用out关键字

网站公告

今日签到

点亮在社区的每一天
去签到