HOME
BLOG
Class专题(1)
9月 02 2022

Class 相关内容:

| 概念:

定义一个类后,就必须实例化才能使用。

实例化就是创建一个对象的过程。

实例化: 类 对象 = new 类();

  • 类的声明是以关键字 class 开始,后跟 类的名称 组成的。

  • 类的实例是以关键字 new 开始,后跟 类的名称 组成的。

课程内容 1 :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/*
 *  在类的内部声明的变量或函数,若想访问,必须通过 类名 进行访问
 *  static 声明的类内的变量,称之为 类的静态成员变量
 *  static 声明的类内的函数,称之为 类的静态成员函数
 */

public class MyClass
{
    public static int a = 10; // static 
    public static void Func1() // static
    {
        Debug.Log("Func1 Called");
    }
}

public class StudyBaseClass : MonoBehaviour
{
    void Start()
    {
        // 创建类的实例
        // MyClass myClass = new MyClass();
        // MyClass myClass = new MyClass();
        // int b = myClass.a;
        // Debug.Log(b);

        int b = MyClass.a;
        Debug.Log(b);
        MyClass.Func1();
    }

课程内容 2 :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// 构造函数 发生在 new 实例时,会被自动执行; 构造函数可以携带参数,当你显示写了自己的构造后,系统 将不再给你提供默认的无参构造函数
// 析构函数 当 当前类对象 被销毁时,会被自动执行

// 作用域的问题
// 函数内声明的变量(包括类对象),在执行完本函数时,会被自动销毁
// 但是,在类内声明的成员变量(包括类对象),只有当前类被销毁时,那它管理的其他变量(包括类对象)才会被销毁

// public & private 理解

namespace MySpace
{
    public class MyClass
    {
        private int a = 10;
        public MyClass() // 无参数构造函数
        {
            Debug.Log("MySpace 命名空间下的 MyClass 的【构造函数】执行");
        }
        public MyClass(int value) // 有参数构造函数
        {
            Debug.Log("传入的值是 value = " + value + ",a 的默认值 = " + a);
            a = value;
            Debug.Log("传入的值是 value = " + value + ",赋值后的 a 的默认值 = " + a);

        }
        ~MyClass()
        {
            Debug.Log("MySpace 命名空间下的 MyClass 的【析构函数】执行");
        }
        /*
        private void Show()
        {
            Debug.Log("MySpace 命名空间下的 MyClass 的【Show】执行");
        }
        */
    }
}

public class StudyBaseClass2 : MonoBehaviour
{
    MySpace.MyClass myClass;

    void Start()
    {
        myClass = new MySpace.MyClass(100);
        // int b = myClass.a;
        // myClass.Show();
    }

    void Update()
    {
        // Input 这个是键盘鼠标监听工具类
        if (Input.GetMouseButton(0)) // 0-鼠标左键 1-鼠标右键 2-滚轮
        {
            Destroy(this.gameObject);
        }
    }
}

面向对象 相关内容:

| 继承:

已有的类被称之为 基类,新的类被称之为 派生类

课程内容:

  • 需求:在控制台下打印出这些多边形的信息

    • 矩形:

      • 名字

      • 颜色

    • 三角形:

      • 名字

      • 颜色

演示:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// 继承:就是将 共用的属性或方法抽离到 父类的过程。 这个思维 称之为 面向对象。
// 访问修饰符:
//          private
//          protected
// 不支持 多重继承

public class Polygon // 基类(父类)
{
    public int Length;
    public int Width;
    public string color;
    public string name;
    private int aaa; // 子类及以下都不可访问(基本等于都不可访问?)
    protected int ccc; // 子类可以访问 类的对象不可访问
}
// 派生类(子类)
class Rectangle : Polygon
{
    public Rectangle()
    {
        int bbb = aaa;
        int ddd = ccc;
    }
    ~Rectangle()
    {

    }
}
// 派生类(子类)
class Triangle : Polygon
{
    public Triangle()
    {

    }
    ~Triangle()
    {

    }
}

public class Extern1 : MonoBehaviour
{
    void Start()
    {
        Rectangle rectTangle = new Rectangle();
        rectTangle.Length = 3;
        rectTangle.Width = 4;
        rectTangle.name = "矩形";
        rectTangle.color = "红色";
        Debug.Log(rectTangle.color + "多边形" + rectTangle.name + ",长" + rectTangle.Length + ",宽" + rectTangle.Width);

        Triangle triangle = new Triangle();
        triangle.Length = 3;
        triangle.Width = 4;
        triangle.name = "三角形";
        triangle.color = "黄色";
        Debug.Log(triangle.color + "多边形" + triangle.name + ",长" + triangle.Length + ",宽" + triangle.Width);
    }
}

| 封装:

隐藏技术细节,仅暴漏外部调用者关心的接口。

  • 将实现细节,通过接口的形式 暴露给第三方,而不需要关心实现细节。
  • 两个关键字: virtual override

演示:

public enum POLYGON
{
    Rectangle,
    Triangle,
}
public class Polygon // 基类(父类)
{
    public int Length;
    public int Width;
    public string color;
    public string name;

    public POLYGON emPolygon;
    public float Area; // 面积

    // 这种思维 就叫封装。(该例子是基础的封装)
    public void ShowBaseInfo()
    {
        Debug.Log(color + "多边形" + name + ",长" + Length + ",宽" + Width);

    }
    public virtual void CalcArea() // virtual 代表虚函数,意味着 子类可以覆盖其实现;如果子类不覆盖,那将使用父类的同名函数
    {

    }
}

// 派生类(子类)
class Rectangle : Polygon
{
    public Rectangle()
    {
        //int bbb = aaa;
        //int ddd = ccc;
    }
    ~Rectangle()
    {

    }

    public override void CalcArea()  // override 代表覆盖
    {
        Area = Length * Width;
    }
}
// 派生类(子类)
class Triangle : Polygon
{
    public Triangle()
    {

    }
    ~Triangle()
    {

    }
    public override void CalcArea()  // override 代表覆盖
    {
        Area = Length * Width / 2;
    }
}
public class Extern1 : MonoBehaviour
{
    void Start()
    {
        // 矩形面积 = 长 * 宽
        Rectangle rectTangle = new Rectangle();
        rectTangle.emPolygon = POLYGON.Rectangle;
        rectTangle.Length = 3;
        rectTangle.Width = 4;
        rectTangle.name = "矩形";
        rectTangle.color = "红色";
        rectTangle.ShowBaseInfo();
        rectTangle.CalcArea();
        Debug.Log("矩形的面积:" + rectTangle.Area);

        // 三角形面积 = 长 * 宽(高)/2
        Triangle triangle = new Triangle();
        triangle.emPolygon = POLYGON.Triangle;
        triangle.Length = 3;
        triangle.Width = 4;
        triangle.name = "三角形";
        triangle.color = "黄色";
        triangle.ShowBaseInfo();
        triangle.CalcArea();
        Debug.Log("三角形的面积:" + triangle.Area);
    }
}

| 多态

  • 静态多态(编译时):C#提供两种技术实现静态多态性。分别为 函数重载 和 运算符重载。

  • 动态多态(运行时):在运行时,根据实例对象,执行同一个函数的不同行为。

演示:

public class Polygon
{
    public virtual void Show()
    {
        Debug.Log("Polygon Show");
    }
}

class Rectangle : Polygon
{
    public override void Show()
    {
        Debug.Log("Rectangle Show");
    }
} 
class Triangle : Polygon
{
    public override void Show()
    {
        Debug.Log("Triangle Show");
    }
}
public class Extern1 : MonoBehaviour
{
    void Start()
    {
        // 运行时多态,就是运行时无法确认调用哪个方法,只有在运行时才能确定的方法,这种行为 称之为多态
        // 注意:
        //           子     =      父     是不可以的,只能 子 给 父 赋值。  
        //           父     =      子
        Polygon baseParent1 = rectTangle;
        Polygon baseParent2 = triangle;

        baseParent1.Show();
        baseParent2.Show();
    }
}

| 重载和覆盖的区别

  • 重载:发生在任何关系中,只要保证 函数名字一致,参数不一致(带参数和不带参数,带参数顺序不一致,或者是参数个数不一致也是可以的),即可实现。

  • 覆盖:发生在 继承关系中,通过 virtual 和 override;函数名 以及 函数参数 是一模一样的

演示:

public class Polygon // 基类(父类)
{
    public void ShowFunc()
    {

    }
    public void ShowFunc(int a)
    {

    }
    public void ShowFunc2(int a,string b,float c)
    {

    }
    public void ShowFunc2(float c,int a, string b)
    {

    }
    public void ShowFunc2(string b, float c,int a)
    {

    }
} 
class Rectangle : Polygon
{
    public void ShowFunc(string str)
    {

    }
} 
public class Extern1 : MonoBehaviour
{
    void Start()
    {
        Rectangle rectTangle = new Rectangle();
        rectTangle.emPolygon = POLYGON.Rectangle;
        rectTangle.Length = 3;
        rectTangle.Width = 4;
        rectTangle.name = "矩形";
        rectTangle.color = "红色";
        rectTangle.ShowBaseInfo();
        rectTangle.CalcArea();
        // rectTangle.ShowFunc();  这两个就是重载
        // rectTangle.ShowFunc2();
        Debug.Log("矩形的面积:" + rectTangle.Area);
    }
}

| this 和 base 关键字的作用

  • this:可访问到 当前类 能访问到的 属性或方法

  • base:只能够从 父类(基类 里边访问 属性和方法



类的更多表现形式 相关内容:

| 静态类

  • 类可以声明为 static这将变成一个静态类,不得被继承,特点是仅包含静态成员或常量。

  • 一般用在 工具类

  • 特点:

    • (1)静态类,不允许有实例构造函数,只允许存在一个静态构造函数,(暂记:静态类的静态构造函数,经测试发现,并不会被执行)

    • (2)静态类,不允许被实例化,意味着 不能使用 new 关键字创建静态类的实例;

    • (3)静态类,内部成员,必须是 静态成员 / 常量

    • (4)静态类,无法作为基类派生

  • 补充知识点:

    • const

      • 在类内声明的 const 常量

        • (1)外部访问时,必须通过 类名进行访问;但不可修改值

        • (2)只能在声明时 初始化,不允许在任何其他地方对其初始化(包括构造函数)

        • (3)在某种程度,被 const 修饰的变量(常量),不可变值

    • readonly

      • 在类内声明的 readonly 常量

        • (1)readonly const,不可共同修饰一个类型(基本数据类型 + 自定义数据类型)

        • (2)readonly修饰的类型,不可被类的实例进行访问;但不可修改值

        • (3)readonly的初始化,只能发生在构造函数或者声明中

    • 变量访问修饰符的控制:

      • (1)可通过访问修饰符构成的语法块,来实现 类似 外部只读的效果; getset 以及学习一下 value 赋值和访问代码的执行流程
    • 静态构造函数:

      • (1)静态构造函数,不需要增加访问修饰符

      • (2)静态构造函数,无论多少实例 都只被调用一次,而且是只被系统自动调用一次

演示:

public static class MyClass4
{
    static MyClass4()
    {
        Debug.Log("父类的构造函数执行");
    }
}

static class MyClass3 : MyClass4
{
    public const int mValue1 = 10;
    public static int mValue;

    public static void Show()
    {

    }
    static MyClass3()
    {

    }

    public const int mValue = 20;
    public readonly  int mValue2;
    public int mValue3 { get; private set; }

    private int m_Value4;
    public int mValue4
    {
        get
        {
            return m_Value4;
        }
        set
        {
            m_Value4 = value;
        }
    }

    public void Show()
    {

    }
}

public class StaticClass : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        MyClass3 myClass3 = new MyClass3();
        // int a = myClass3.mValue;
        int a = MyClass3.mValue;
        int b = myClass3.mValue2;
        // myClass3.mValue3 = 1000;
        // myClass3.mValue2 = 1000;
        // int d = myClass3.mValue4;
        // myClass3.mValue4 = 1000;

        MyClass3 myclass1 = new MyClass3();
        MyClass3 myclass2 = new MyClass3();
    } 
}

| 密封类

  • 小概念:类可以声明为 sealed ,这将变成一个密封类。

  • 特点:

    • (1)不允许被继承

    • (2)sealedabstract 不能共存

    • (3)密封类内的函数,不允许增加 sealed 关键字

    • (4)密封类可以正常继承 - 常见类(普通类、抽象类)、接口

演示:

public abstract class MyClass8 
{

}

public interface MyInterface // 接口
{

}

public sealed class MyClass10
{

}

public sealed class MyClass9 //: MyClass10
{
    public void Show()
    {

    }

    /*
    public sealed void Show2()
    {

    }
    */
}

| 抽象类

  • 小概念:类可以声明为 abstract ,这将变成一个抽象类。

  • 特点:

    • (1)不允许实例化

    • (2)支持构造函数

    • (3)抽象类可继承抽象类

    • (4)静态构造函数 只执行一次;但是其他的构造函数 则根据不同实例,分别在再次调用

    • (5)允许 virtual 虚函数

    • (6)若函数声明为 abstract,则不允许包含函数体;子类,必须显示覆盖 父类的该方法

演示:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class MyClass5
{

}

public abstract class MyClass6 //: MyClass5
{
    public MyClass6() { Debug.Log("MyClass6 默认构造函数"); }
    static MyClass6() { Debug.Log("MyClass6 静态构造函数"); }

    public void Show1()
    {
        Debug.Log("普通 Show1");
    }

    public virtual void Show2()
    {
        Debug.Log("MyClass6 virtual Show2");
    }

    public abstract void Show3();
}

public class MyClass7 : MyClass6
{
    public MyClass7() { Debug.Log("MyClass7"); }

    public override void Show2()
    {
        Debug.Log("MyClass7 override Show2");
    }

    public override void Show3()
    {

    }
}

public class Abstract : MonoBehaviour
{
    void Start()
    {
        // MyClass5 myclass5 = new MyClass5();
        MyClass7 myclass7 = new MyClass7();
        myclass7.Show1();
        myclass7.Show2();

        // MyClass7 myclass8 = new MyClass7();
    }
}

| 泛型类 & 泛型方法

  • 小概念:类名后可以添加 <T1.T2.T3...> 这将变成一个泛型类。泛型类 T1.T2.T3 可以通过 where 关键字 来限定类型。

  • 特点:

    • 在声明时可以不指定具体的类型,但是在 new 实例化时必须指定 T类型

    • 可指定泛型类型约束

    • 如果子类也是泛型的,那么继承的时候可以不指定具体类型

  • 一般用在:处理一组功能一样,仅类型不同的任务时

  • 泛型约束 注意点:

    • .NET 含有以下五种泛型约束:

      • where T:class | T 必须是一个类

      • where T:struct | T 必须是一个结构类型

      • where T:new( ) | T 必须要有一个无参数的构造函数

      • where T:NameOfBaseClass | T 必须继承名为 NameOfBaseClass 的类

      • where T:NameOfInterface | T 必须实现名为 NameOfInterface 的接口

演示:

// 需求:
//      在类里边定义一个数组,让这个类具备 设置数据 和 访问数据 的能力

public class BaseParent <T,X>
{

}

/*
public class Son <T,X> : BaseParent <T,X>
{

}

public class Son : BaseParent<int, string>
{

}

public class Son<T, X,Y,A> : BaseParent<T, X>
{

}
*/

public class Son : BaseParent<int, string>
{
    public void Show<X>(X A)
    {
        Debug.Log("A = " + A);
    }
}

/*
public class MyClassType
{
    public int a;

    public MyClassType(int value)
    {
        this.a = value;
    }
}

public class MyClass15 <T> where T:MyClassType
{
    private T[] m_array;

    public MyClass15(int size)
    {
        m_array = new T[size];
    }

    public void Set(int index,T value)
    {
        m_array[index] = value;

    }

    public int Get(int index)
    {
        return m_array[index].a;
    }
}

public class MyClass16<T> where T : string // error
{
    private T[] m_array;

    public MyClass16(int size)
    {
        m_array = new T[size];
    }

    public void Set(int index, T value)
    {
        m_array[index] = value;

    }

    public int Get(int index)
    {
        return m_array[index].a;
    }
}
*/

public class TClass : MonoBehaviour
{
    void Start()
    {
        /*
        MyClass15 myclass = new MyClass15(5);
        myclass.Set(0, 1);
        myclass.Set(1, 2);
        int a = myclass.Get(0);
        int b = myclass.Get(1);
        */

        /*
        MyClass15<string> myclass = new MyClass15<string>(5);
        myclass.Set(0, "极客");
        myclass.Set(1, "教育");
        string a = myclass.Get(0);
        string b = myclass.Get(1);
        */

        /*
        MyClass15<MyClassType> myclass = new MyClass15<MyClassType>(5);
        myclass.Set(0, new MyClassType(1));
        myclass.Set(1, new MyClassType(2));
        // MyClassType a = myclass.Get(0);
        // MyClassType b = myclass.Get(1);

        int a = myclass.Get(0);
        int b = myclass.Get(1);

        Debug.LogFormat("第{0}号位,值:{1}", 0, a);
        Debug.LogFormat("第{0}号位,值:{1}", 1, b);
        */

        Son son = new Son();
        son.Show<string>("str.....");
    }
}

| 接口

  • 小概念:interface + name ,这将变成一个接口。

  • 特点见演示

演示:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface BaseInterface1
{
    void ShowWindow();
    void HideWindow();

    /*
    void Show1()  
    {
        错误的,不能包含函数的实现
    }
    */

    // private void Show3(); 错误的,不能将函数的声明 改为 私有的
}

public interface BaseInterface2
{
    void PlaySound();
    void CloseSound();
}

public interface MyInterface : BaseInterface1,BaseInterface2  // 接口 允许单一继承,也允许多重继承
{

}

public class MyClass16 : MyInterface
{
    // 方法一(常见)
    public void CloseSound()
    {
        throw new System.NotImplementedException();
    }
    public void HideWindow()
    {
        throw new System.NotImplementedException();
    }
    public void PlaySound()
    {
        throw new System.NotImplementedException();
    }
    public void ShowWindow()
    {
        throw new System.NotImplementedException();
    }
    // 方法二(使用修补程序得出的)
    /*
    void BaseInterface2.CloseSound()
    {
        throw new System.NotImplementedException();
    }

    void BaseInterface1.HideWindow()
    {
        throw new System.NotImplementedException();
    }

    void BaseInterface2.PlaySound()
    {
        throw new System.NotImplementedException();
    }

    void BaseInterface1.ShowWindow()
    {
        throw new System.NotImplementedException();
    }
    */
}

public class BaseClass1
{

}

public class BaseClass2
{

}

/*
public class Son1 :BaseClass1,BaseClass2
{
    错误的 单个类不能继承多个类
}
*/


// 类只允许继承单个类,但可以同时继承多个接口
public class Son1 : BaseClass1,BaseInterface1, BaseInterface2
{
    void BaseInterface2.CloseSound()
    {
        throw new System.NotImplementedException();
    }

    void BaseInterface1.HideWindow()
    {
        throw new System.NotImplementedException();
    }

    void BaseInterface2.PlaySound()
    {
        throw new System.NotImplementedException();
    }

    void BaseInterface1.ShowWindow()
    {
        throw new System.NotImplementedException();
    }
}

public class TInterface : MonoBehaviour
{
    void Start()
    {
        // BaseInterface1 inter = new BaseInterface1(); 错误的,接口不可被实例化
    }
}

| 接口 & 抽象类

  • 相同点:

    • (1)关于实例化

      • 两者都不允许实例化
    • (2)都支持只声明函数,不包含实现

    • (3)关于派生类

      • 都必须去实现 接口或抽象类的方法
  • 不同点

    • (1)变量

      • 接口 不允许声明变量;而抽象类是可以的
    • (2)构造函数

      • 接口 不允许构造函数(包括普通构造函数和静态构造函数);而 抽象类 是可以的
    • (3)函数实现

      • 接口 不允许函数实现;而抽象类是可以的
    • (4)访问修饰符

      • (1)默认 public; 不允许改变为 private

      • (2)默认 private; 函数前面若是 abstract,那访问修饰符也不能是 private; 但是 非 abstract声明的函数 是允许 private protected

    • (5)是否多重继承

      • 接口 允许多重继承多个接口;而抽象类是不允许多重继承多个类的

演示:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface BaseInteface_1
{

}


public interface BaseInteface_2
{

}

public interface MyInterface : BaseInteface_1, BaseInteface_2
{
    // public int a;

    //MyInterface();
    //static MyInterface();

    //void Show() { }

    //internal void Show();

    void ShowInterface();
}

public abstract class BaseAbstract_1
{

}
public abstract class BaseAbstract_2
{

}


public abstract class MyAbstruct //: BaseAbstract_1, BaseAbstract_2
{
    // public int a;

    //MyAbstruct() { }
    //static MyAbstruct() { }

    //void Show() { }

    //internal abstract void Show();

    public abstract void ShowAbstruct();
}

public class MyClass18 : MyInterface
{
    public void ShowInterface()
    {
        throw new System.NotImplementedException();
    }
}

public class MyClass19 : MyAbstruct
{
    public override void ShowAbstruct()
    {
        throw new System.NotImplementedException();
    }
}

public class CompareInterfaceAbstract : MonoBehaviour
{
    void Start()
    {
        //MyInterface interfaceTest = new MyInterface();
        //MyAbstruct abstructTest = new MyAbstruct();
    }
}


👾 - Morikiiii - 👾

C# Study