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)可通过访问修饰符构成的语法块,来实现 类似 外部只读的效果;
get
和set
以及学习一下 value 赋值和访问代码的执行流程
- (1)可通过访问修饰符构成的语法块,来实现 类似 外部只读的效果;
静态构造函数:
(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)
sealed
和abstract
不能共存(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();
}
}