零基础自学C#——Part4:类的表现形式
上一部分讲解了类(如何创建类,类的实例化等)以及一些基于类上的基本操作,比如继承,多态,封装,重载和重写(覆盖),这一部分,我们将细分化的介绍类的更多表现形式。
一、静态类
就像我们上一部分说的那样,我们在类内使用static声明的变量,称为类的静态成员变量,这样的函数称为类的静态成员函数。
为什么我们要用静态类呢?一般当这个类很频繁被调用,定义成静态的就不用每次给他实例化了,直接用类去调用可以了,像工具类一般都定义成静态的,这样不用每次实例化了,直接用类名去调用(普通类调用时,必须先要给他new 下,才能去调用)
特点:(1)不能被实例化、不能被继承
(2)不能包含实例构造函数,但是可以包含一个静态构造函数,且静态构造函数不可被调用
1:静态修饰符
const:在类内声明的const常量,在类外访问时,只能通过类名进行访问(不可通过实例化类名)
MyClass myClass= new Myclass();
int a = MyClass.mVaule 而不可为myClass.mVaule
在类内声明的const常量,只能在声明时进行初始化,不允许任何其他地方对其初始化
public const int mVaule1=10;
在某种程度,被const修饰的常量,不可变值
readonly:在类内声明的readonly,不可与const共同修饰一个数据类型
public readonly const int mVaule; //这样的声明方式不允许
readonly修饰的类型,可以被类的实例进行访问,但不可修改值。
readonly的初始化,只能发生在构造函数或声明中。
2:静态构造函数
①静态构造函数,不需要增加访问修饰符
②静态构造函数,无论多少实例,都只被调用一次,而且都只是被系统自动调用一次。
public class Class3;
{static Class4(){Debug.Log("Father");}
}public class Class4: Class3
{public Class3(){Debug.Log("Son");}}public calss ClassTest:MonoBehaviour
{void Start(){Class3 iClass1 =new Class3();Class3 iClass2 =new Class3();}
}
如上代码,父类声明了静态构造函数,在输出时,只输出一次Father,而输出两Son。
3:静态类
①:静态类不允许有实例构造函数,只允许存在一个静态构造函数
②:不能被实例化
③:静态类内部成员,必须是静态成员,函数也必须是静态成员函数
public static class Myclass
{public const int mVaule=10; //可以添加静态修饰符public static int mVaule; //成员必须是静态public static void Show(){} //函数必须是静态
}
④:静态类无法被继承
二、抽象类
可以在类前加static,使之成为抽象类,它一般是为子类提供设计思想,配合多态用于代码的架构设计。
特点:
不能被实例化
抽象类可以继承抽象类
支持构造函数,静态构造函数只执行一次;其他构造函数会根据实例不同,分别再次调用
允许virtual虚函数
抽象类中不一定有抽象方法,但是有抽象方法的类一定是抽象类,但抽象函数不允许有函数体,且必须显示覆盖父类的该方法。
public abstract class MyClass6
{public MyClass6(){Debug.Log("MyClass6默认构造函数");}static MyClass6(){Debug.Log("MyClass6静态构造函数"); //静态构造函数只执行一次}public void Show1() //普通构造函数会根据实例多次调用{Debug.Log("普通Show1");}public virtual void Show2() //可以使用virtual{Debug.Log("Myclass6 virtual Show2");}public abstract void Show3(); //定义抽象方法,不允许有函数体,且在实现时候必须使用覆盖}
public class MyClass7:MyClass6 //抽象类可以继承
{public MyClass7(){Debug.Log("MyClass7");}public override void Show2() //Show2的重写{Debug.Log("MyClass7 override Show2");}public override void Show3() //Show3抽象过了,想实现也必须重写{}
}public class Abstract : MonoBehaviour
{void Start(){Myclass7 myClass7=new Myclass7();Myclass7 myClass8=new Myclass7();}
如上的输出结果,则只输出一次静态构造函数
三、密封类(接口)
密封类一般用于防止重写某些类或接口影响功能的稳定,在class前加sealed,变为密封类。
特点:不能被继承,但可以继承别的类或者接口
抽象abstruct和sealed不能共存
密封类内的成员函数,不得声明成sealed
public sealed class MyClass8
{}public class MyClass9:MyClass8 //不允许被继承{}public class Myclass9
{public sealed class Myclass10:Myclass9 //允许继承其他类{}
}
四、泛型类&泛型方法
我们在处理一组功能相同,仅类型不同的任务的时候,可以在类名后添加<T1,T2,T3..>,将变成一个泛型类,泛型T1,T2,T3,可以通过where关键字来限定类型。
特点:
在声明时可以不指定具体的类型,但是new实例化时必须指定T类型
可指定泛型类型约束
如果子类也是泛型的,那么继承的时候可以不指定具体类型
1:泛型类的效率
#需求:在类内定义一个数组,让这个类具备设置数据和访问数据的能力
①:不使用泛型类
我们必须分别创建两个类,分别用来存储int类型和string类型的数组
public class MyClass //创建一个类用来存储int类型的数组
{private int[]m_array; //声明了私有Int类型的数组m_arraypublic MyClass(int size) //构造函数,设置容量{m_array=new int[size];}public void Set(int index,int value) //设置数据的方法,int类型的下标和数据{m_array[index]=value; }public int Get(int index) //设置了访问数据的方法{return m_array[index]; //返回Index }public class MyClass1 //创建一个类用来存储string类型的数组
{private string[]m_array; //声明了私有string类型的数组m_arraypublic MyClass1(string size) //构造函数,设置容量{m_array=new string[size];}public void Set(int index,string value) //设置数据的方法,string类型的下标和数据{m_array[index]=value; }public string Get(int index) //设置了访问数据的方法{return m_array[index]; //返回Index }}public class Tclass
void Start()
{MyClass myClass= new MyClass(5); //实例化后设置容量myClass.Set(0,1); //设置数据myClass.Set(1,2);int a=myClass.Get(0);int a=myClass.Get(1);Debug.LogFormat("第(0)号位,值:{1}",0,a);Debug.LogFormat("第(1)号位,值:{1}",1,b);
}
②使用泛型
public class MyClass<T> //创建一个泛型类,表示方法如图
{private T[]m_array; //声明了私有T类型的数组m_arraypublic MyClass(int size) //构造函数,设置容量{m_array=new T[size]; //构造函数也使用T类型}public void Set(int index,T value) //设置数据的方法,T类型的下标和数据{m_array[index]=value; }public T Get(int index) //设置了访问数据的方法{return m_array[index]; //返回Index }public class Tclass
void Start
{ //在原本T的位置可以改成string,这样就可以存储string类型的数据了
MyClass<string> myClass = new MyClass<string>(5);
myClass.Set(0,"1");
myClass.Set(1,"2");
string a =myClass.Get(0);
string b =myClass.Get(1);
Debug.LogFormat("第(0)号位,值:{1}",0,a):
Debug.LogFormat("第(1)号位,值:{1}",0,b):
}
2:存储类的数据类型
①:不使用where限定
public calss MyClassType //创建需要被存储的类
{public int a;public MyClassType(int value) //创建类的成员{this.a=value;}
}public class MyClass<T>
{private T[]m_array; public MyClass(int size) {m_array=new T[size]; }public void Set(int index,T value){m_array[index]=value; }public T Get(int index) {return m_array[index]; }void Start()
{MyClass<MyClassType> myClass =new MyClass<MyClassType>(5); //在实例化的时候也需要改变类型myClass.Set(0,new MyClassType(1));myClass.Set(1,new MyClassType(2));MyClassType a=myClass.Get(0);MyClassType b=myClass.Get(1);Debug.LogFormate("第(0)号位,值:{1},",0,a,a);Debug.LogFormate("第(1)号位,值:{1},",1,b,a);
}
②使用where限定
public calss MyClassType //创建需要被存储的类
{public int a;public MyClassType(int value) //创建类的成员{this.a=value;}
}public class MyClass<T> where T:MyClassType //使用where来限定T的类型
{private T[]m_array; public MyClass(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; }void Start()
{MyClass<MyClassType> myClass =new MyClass<MyClassType>(5); //在实例化的时候也需要改变类型myClass.Set(0,new MyClassType(1));myClass.Set(1,new MyClassType(2));int a=myClass.Get(0); //直接使用int访问即可int b=myClass.Get(1);Debug.LogFormate("第(0)号位,值:{1},",0,a);Debug.LogFormate("第(1)号位,值:{1},",1,b);
}
NET含有以下五种泛型约束:
1:where T:class|T 必须是一个类
2:where T:struct|T 必须是一个结构类型
3:where T:new()|T 必须要有一个无参数的构造函数
4:where T:NameOfBaseClass |T 必须继承名为NameOfBaseClass的类
5:where T:NameOfInterface |T 必须实现名为NameOfInterface的接口
3:泛型方法
public void Show<X>(X A) //这里的X代表使用泛型的类型,A代表你创建的类型的名称
{Debug.Log("A="+A);
}void Start()
{Son son= new Son();son.Show<string>("string"); //在外部调用的时候会自动显示需要的类型,后方括号内可写名称
}
4:泛型在继承中的使用,子类给父类限定方法
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> //父类延迟赋值的同时,给自己增加了类型Y,A
{}
五、接口
接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因
此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。
可以使用interface+name,就形成了一个接口。
下面这位博主讲的更为详细。
JAVA基础——接口(全网最详细教程)_刘扬俊的博客-CSDN博客_java接口
特点:
接口只声明接口函数,不包含实现
接口函数访问修饰符,必须是public,默认也是public
接口成员函数的定义时派生类的责任,接口提供了派生类应遵循的标准接口
接口不可被实例化
接口可以继承其他接口,接口允许多重继承
1:接口的具体代码实现
public interface BaseInterface1 //接口的引入,interface +name
{void ShowWindow(); //接口可声明函数void HideWindow();!!! void Show1() //接口不可包含函数体{!!! }!!! private void Show3(); //不能将函数的声明改为私有的
}public interface BaseInterface2
{void PlaySound();void CloseSound();
}
public interface MyInterface:BaseInterface1,BaseInterface2 //接口允许单一继承,也允许多重继承{}
public class MyClass16
{}
public class Tinterface : MonoBehaviour
{void Start(){!!! BaseInterface inter =new BaseInterface(); //接口不可以被实例化}
2:接口和抽象类的区别和共同点
①:区别
接口不允许声明变量;而抽象类可以
public interface Myinterface
{public int a; 不可!!!
}public abstract calss MyAbstract
{public int b;
}
接口不允许有构造函数(普通和静态),而抽象类可以
public interface Myinterface
{Myinterface();static Myinterface(); 不可!!!
}public abstract calss MyAbstract
{MyAbstract();static MyAbstract();
}
接口不允许函数实现,而抽象类可以
接口允许多重继承,而抽象类不可以多重继承
{接口默认的访问修饰符是public,不允许改为private
抽象类默认的访问修饰符是private,函数前面若是abstract,那访问修饰符也不能是private,但是非abstract声明的函数允许private,protected. }
②:共同点
两者都不允许实例化
函数都支持只声明,不实现
他们的派生类都必须去实现接口或抽象类的方法
public interface MyInterface
{void Show1();
}public abstract MyAbstract
{void Show2();
}public class MyClass:Myinterface
{public void ShowInterface() //实现interface中的方法{}
}
public class MyClass:MyAbstract
{public override void ShowAbstract() //实现abstract中的方法{}
}
六、结构体Struct
结构体是由一系列具有相同类型或不同类型的数据构成的数据集合,也叫结构。它使得一个单一变量可以存储各种类型的相关数据,我们使用Struct+name结构来声明一个结构体。
特点:
结构体可以带方法,字段,索引,属性,运算符,方法和事件
结构体可以定义构造函数,但不能定义析构函数,无参构造函数(自动定义,且不可改变)
结构体不能继承其他的结构体或类,但可以实现一个或多个接口
结构体不能作为其他结构或类的基础结构
结构成员不能指定为abstract、virtual、protected
结构体不能实例化
1:struct和class的异同
①相同点:
都支持静态构造函数、自定义函数
struct MyStruct
{Static MyStruct(){}public void Show(){}
}class MyClass
{Static MyClass(){}public void Show(){}
}
结构体和类对于const修饰的变量的使用方式是一样的
访问函数时,结构体和类都必须进行初始化才能访问
MyClass myClass = new MyClass();
myClass.Show();MyStruct myStruct = new MyStruct();
myStruct.Show();
②不同点:
结构体不允许定义无参构造函数,只允许定义有参构造函数,但类都可以
struct MyStruct
{public MyStruct(int value){}public MyStruct() !!!不可{}
}
结构体不允许定义析构函数,类可以
结构体不允许声明为virtual,但类可以
struct MyStruct
{public virtual void Show2(){} !!!不可
}
结构体不允许声明为abstratct ,但类可以
结构体不允许声明protected,但类可以
结构体声明的全局普通变量(不带修饰符),不能在声明时直接赋值,只能在构造函数里赋值,但类哪里都可以
struct MyStruct
{public int a;public MyStruct(int value){a=value}
}class MyClass
{public int a=2000;
}
结构体声明的全局readonly变量,只能在构造函数里赋值,而类都可以
struct MyStruct
public readonly string str;
public MyStruct(int value) //只能在有参构造函数赋值
{a=value;str="20";
}class MyClass
public readonly string str="20"; //直接赋值
或
public read only string str;
public MyClass(int value){str="20"} //构造函数赋值
结构体之间不能相互继承,但是类与类可以
结构体访问成员变量,给变量显示赋值可直接访问,而类必须实例化后才可访问
结构体如果不通过new初始化,是不可以直接访问内部变量(const除外)
MyStruct myStruct;
myStruct.a=2000;
int b =myStruct.a;MyClass myClass = new MyClass();
int a =myClass.a;
结构体的new并不会在堆上分配内存,仅是调用结构体的构造函数初始化而已
类的new会在堆上分配内存,而且也会调用类的构造函数进行初始化
零基础自学C#——Part4:类的表现形式相关推荐
- 零基础自学应用近世代数 第1章 引言和预备知识 1.1 几类实际问题 1.1.1 一些计数问题
零基础自学应用近世代数 文章目录 零基础自学应用近世代数 第1章 引言和预备知识 1.1 几类实际问题 1.1.1 一些计数问题 [1]项链问题 [2]分子结构的计数问题 [3]正多面体着色问题 [4 ...
- 零基础学python用什么书-零基础自学python3 好用的入门书籍推荐
零基础自学python3 好用的入门书籍推荐,博学谷小班整理了六本数,推荐阅读 <Python for data analysis>.<Python数据分析与挖掘实战>.< ...
- python3入门书籍-零基础自学python3 好用的入门书籍推荐
零基础自学python3 好用的入门书籍推荐,博学谷小班整理了六本数,推荐阅读 <Python for data analysis>.<Python数据分析与挖掘实战>.< ...
- 自学python需要多长时间-零基础自学python要多久?
原标题:零基础自学python要多久? 如果是自学,从零基础开始学习Python的话,依照每个人理解能力的不同,大致上需要一年半左右的时间,至于能不能学好要看你自己的领悟了,至于找到工作那就不好说了. ...
- 零基础学python用哪本书好-零基础自学python3 好用的入门书籍推荐
零基础自学python3 好用的入门书籍推荐,博学谷小班整理了六本数,推荐阅读 <Python for data analysis>.<Python数据分析与挖掘实战>.< ...
- 0基础学python要多久-零基础自学python要多久?
原标题:零基础自学python要多久? 如果是自学,从零基础开始学习Python的话,依照每个人理解能力的不同,大致上需要一年半左右的时间,至于能不能学好要看你自己的领悟了,至于找到工作那就不好说了. ...
- 零基础自学UI设计要看什么书籍和资料
本文由:"学设计上兔课网"原创,图片素材来自网络,仅供学习分享 零基础自学UI设计要看什么书籍和资料?学习UI设计的方法有很多,有些会选择报名UI设计培训班学习,也有的小伙伴会选择 ...
- 零基础自学平面设计需要学些什么?
作为一个新手从零基础开始学习平面设计,首先明白的是平面设计是什么,当你能够自己解释平面设计,让你身边的人明白的时候,基本你就是开始入门了. 同时你还要明白的,学习平面设计需要掌握哪些基本知识,和行业性 ...
- 非零基础自学Golang 第1章 走进Go 1.2 Go语言官方文档 1.3 学好Go 的建议
非零基础自学Golang 文章目录 非零基础自学Golang 第1章 走进Go 1.2 Go语言官方文档 1.3 学好Go 的建议 1.3.1 了解语言特性及自身需求 1.3.2 动手写代码 1.3. ...
最新文章
- gitkraen_超详细!Github团队协作教程(Gitkraken版)
- SpringCloud:Hystrix 熔断机制(基本配置、服务降级、HystrixDashboard服务监控、Turbine聚合监控)
- Ubuntu开发环境搭建
- JAVA岗位比嵌入式岗位_java嵌入式职业选择?
- 情人节,怎么同时约会女神和女朋友
- android 系统(8)---Android 学习网站汇总
- oracle密码重用,关于Oracle 9i数据库密码重用规则分析
- C语言的常用字符串操作函数(一)
- js获取可视区域高度
- 关于返回一个整数数组中最大子数组的和的问题(续01)
- 和浏览器并发请求数有关的一些前端技术
- 常见面试题汇总 —— C语言
- thinkpad s5黑将摄像头最新驱动_第一款以iOS方式运行的安卓手机:联想新机S5黑科技震撼来袭!...
- 在线工具 将图片透明化
- ios应用中调用系统电话、浏览器、地图、邮件等 以及打开其他应用(如qq,msn)
- 针式 PKM 个人知识管理软件 帮助
- proxmox VE开NAT小鸡 无法联网,怎么开NAT模式
- c语言静态检测工具,静态代码检测工具---PC-lint(for c/c )
- K-Means算法实现网页聚类
- 2022元宇宙十大商业魔咒