抽象类和多态
抽象父类和具体子类规则
-
抽象类必须使用abstract关键字
-
抽象方法只能出现在抽象类中.抽象方法必须使用abstract关键字.
-
抽象类的抽象方法不能被实现
-
抽象类可以有非抽象普通方法
-
抽象类的对象不能new实例化(即只有具体类的对象才能实例化)
-
具体子类实现父类的抽象方法时需要使用override关键字
-
多态:可以使用抽象父类的对象(抽象类不能new)引用它的具体子类对象
abstract class Food {//抽象类必须使用abstract关键字
//抽象方法必须使用abstract关键字
public abstract void Eaten();//抽象类的抽象方法不能实现
public void Test() {//抽象类可以有具体方法实现
Console.WriteLine("Food.test()非抽象的普通方法实现");
}
}
class Apple : Food {
public override void Eaten() {//子类实现抽象父类的抽象方法
Console.WriteLine("苹果真好吃");
}
}
class Drink : Food {
public override void Eaten() {//子类实现抽象父类的抽象方法
Console.WriteLine("饮料真好喝");
}
}
class Program {
static void Main(string[] args) {
//Food x = new Food();//错误!抽象类不能new
//多态:抽象父类对象引用它的具体子类对象
Food a = new Apple();
Food d = new Drink();
a.Eaten();//抽象父类对象(引用子类Apple对象)调用子类Apple.Eaten()方法
d.Eaten();//抽象父类对象(引用子类Drink对象)调用子类Drink.Eaten()方法
a.Test(); //抽象父类对象调用自身普通方法
Console.ReadKey();
}
}
静态类
堆区:存放数组,对象,字符串变量等;
栈区:自动变量,比如 int i之类;
静态区:存放静态类(的成员),全局一直存在.
常量区:存放const常量,字面值常量例如"hello"(注意不是字符串变量)
代码区:存放代码
关于静态的规则
-
非静态类可以有静态成员:静态的字段,属性,方法-它们只能通过类(而非实例对象)调用
-
静态类不能实例化.
-
静态类只能有静态成员和常量,通过类调用.
class NormalClass {
public static double PI = 3.1415;
public void ShowInfo(){
Console.WriteLine("我是非静态类NormalClass的非静态方法ShowInfo()");
}
public static void ShowStaticInfo() {
Console.WriteLine("我是非静态类NormalClass的静态ShowStaticInfo()方法");
}
}
static class StaticClass {
public static double PI = 3.1415;
//public void ShowInfo(){ //错误!静态类不能有非静态(方法)成员
// Console.WriteLine("我是静态类StaticClass的非静态ShowInfo()方法");
//}
public static void ShowStaticInfo() {
Console.WriteLine("我是静态类StaticClass的静态ShowStaticInfo()方法");
}
}
class Program{
static void Main(string[] args) {
//非静态类直接访问静态成员,无须new1个对象
Console.WriteLine("NormalClass.PI = " + NormalClass.PI);
//静态类直接访问静态成员
Console.WriteLine("StaticClass.PI = " + StaticClass.PI);
NormalClass.ShowStaticInfo();//非静态类直接访问静态方法成员,无须new1个对象
StaticClass.ShowStaticInfo();//静态类直接访问静态方法成员
NormalClass nc1 = new NormalClass();
nc1.ShowInfo();//非静态类访问非静态方法成员是通过它的实例化对象来访问的
//StaticClass sc1 = new StaticClass();//错误!静态类无法实例化!
//StaticClass.ShowInfo();//错误!静态类不能拥有非静态方法!
//sc1.ShowInfo();//错误!静态类不能拥有非静态方法!更不能通过实例化对象调用!
Console.ReadKey();
}
}
-
静态构造方法不允许带参数
-
静态构造方法前不允许有访问修饰符
-
静态构造方法可以存在于静态类中,也可以存在非静态类中
-
静态构造方法最多只调用1次
-
静态构造方法在第一次(仅此一次)访问类的静态static成员时(在普通类中或静态类中)或第一次(仅此一次)实例化对象时调用(在普通类中),并先于其他构造方法(如果存在)调用.
-
如果普通类拥有静态构造方法和带参数的普通构造方法,则只能new带参数的实例对象(不能new无参数实例对象);如果之前静态构造方法没有被调用,则首次new的时候先调用无参数的静态构造方法,再调用普通的带参数构造方法;第2次起再new的时候,只调用带参数的普通构造方法(因为静态构造方法最多只调用1次)
//静态构造方法:不允许有访问修饰符,不许有参数
public class NormalClass{//普通类
static NormalClass() {//普通类静态构造方法
Console.WriteLine("系统调用普通类NormalClass" +
"的静态构造方法static NormalClass().");
}
}
public static class StaticClass {//静态类
public static double PI = 3.1415;//静态类的静态成员
static StaticClass() {//静态类的静态构造方法
Console.WriteLine("系统调用静态类StaticClass" +
"的静态构造方法static StaticClass().");
}
}
public class Program
{
static void Main(string[] args)
{
//首次访问静态类的成员,
//在访问之前系统首次(仅1次)调用静态类的静态构造方法
Console.WriteLine("StaticClass.PI =" + StaticClass.PI);
//首次访问普通类的静态成员或首次new1个对象,
//系统首次(仅1次)调用静态构造方法
NormalClass nc1 = new NormalClass();
//第2次或第N次new对象,系统不再调用静态构造方法
NormalClass nc2 = new NormalClass();
Console.ReadKey();
}
}
归纳:
1静态类:静态构造方法用来管理静态类的初始化;
2普通类:静态构造方法用来管理普通类的静态成员(如果有)的初始化:因为普通构造方法(管理实例对象的初始化)管理不到静态成员.
单例
单例-保证程序在运行期间,一个类最多同时存在1个唯一的对象,访问对象更加方便.
如何单例
1.private构造方法-不让外界创建对象.
2.我们需要在类的内部提供1个静态private实例
3.提供获取实例的接口
class Player {
//玩家的属性
public string name;
public int hp;
public int mp;
//给外部提供1个获取单例实例的接口
public static Player GetInstance() {
if (null == _instance) {//如果实例为空
_instance = new Player();//那就new1个实例
}
return _instance;//将单例实例返回给外部
}
private static Player _instance;//类的private静态单例:禁止外部直接访问
private Player() { }//私有化构造方法:禁止外界new
}
class Program {
static void Main(string[] args) {
Player p1 = Player.GetInstance();//获取单例
p1.name = "铁蛋";
Console.WriteLine("p1名称是" + p1.name);
Player p2 = Player.GetInstance(); //获取到的还是唯一的单例
Console.WriteLine("p2名称是" + p2.name); //p1和p2指向同一Player对象
Console.ReadKey();
}
}
虚方法
子类使用new关键字隐藏父类同名方法.
虚方法和抽象方法对比
1抽象方法必须在抽象类中,虚方法在非抽象的普通类中.
2抽象方法在抽象父类中不能实现.虚方法在父类中可以实现,也可以不实现(加1对内容为空的花括号即可)
3.抽象方法在非抽象子类中必须实现.虚方法在子类中可以实现override,也可以不实现(子类中可以没有这个方法).
多态--父类定义虚方法或虚属性.之后使用父类类型引用子类对象,调用子类重写override的方法和属性.
多态一句话总结:使用父类类型,调用子类对象重写的属性和方法.
class Parent {//父类
//属性为virtual
public virtual string Name {
get { return "老王"; }
}
public void MethodA() {
Console.WriteLine("调用父类方法A.");
Console.WriteLine("-----------");
}
//父类声明为虚方法 -- 实行多态
public virtual void MethodB()
{
Console.WriteLine("调用父类(虚)方法B.");
Console.WriteLine("-----------");
}
}
class Sub : Parent {//子类
//重写override属性 -- 多态
public override string Name {
get { return "老张"; }
}
//使用new关键字隐藏父类同名方法-子类方法替换父类方法
public new void MethodA() {
Console.WriteLine("调用子类方法A.");
Console.WriteLine("----------");
}
//子类重写override父类同名虚方法--多态
public override void MethodB()
{
Console.WriteLine("调用子类方法B.");
Console.WriteLine("-----------");
}
}
class Program {
static void Main(string[] args) {
//使用父类类型引用父类对象
Parent p1 = new Parent();
p1.MethodA();//调用了父类方法A
p1.MethodB();//调用了父类方法B
Console.WriteLine(p1.Name);//父类属性
Console.WriteLine("-----------");
//使用子类类型引用子类对象
Sub s1 = new Sub();
s1.MethodA();//调用了子类方法A
s1.MethodB();//调用了子类方法B
Console.WriteLine(s1.Name);//子类属性
Console.WriteLine("-----------");
//使用父类类型引用子类对象
Parent p2 = new Sub();
p2.MethodA();//结果是调用了父类方法A
p2.MethodB();//结果是调用了子类方法B
//↑多态↑ -- 使用父类类型引用子类对象,调用子类实现的方法
Console.WriteLine(p2.Name);//子类属性-属性也实现多态
Console.WriteLine("-----------");
//使用子类类型引用父类对象
//Sub s2 = new Parent();//错误!不能使用子类类型引用父类对象
//s2.MethodA();//
Console.ReadKey();
}
}