今天是第三天啦
前言
静态与非静态的各个要点,还有就是对继承中的知识进行补足,里氏转换原则的了解,is as运算符的基本常规使用,实现多态的三种方式,虚方法,抽象类,接口
提示:以下是本篇文章正文内容,下面案例可供参考
一、静态与非静态
1.静态的定义:无论什么成员被static修饰,那么这个成员变为静态成员,列如类被修饰则为静态类,方法被修饰则为静态方法,字段则变为静态字段等等…下面将详细对静态与非静态进行分析:
1.如果当前成员是静态成员,那么需要加上static关键字进行修饰。
2.两者之间的调用的区别:
—>静态成员在调用的时候需要使用类名来调用。---->属于类
—>但是非静态成员在调用的时候要求使用对象名来调用。---->对象
3.静态类:静态类中只允许出现静态成员,语法要求
4.非静态类:
—>在非静态类中允许出现静态成员,也允许出现非静态成员。
—>在非静态函数中即允许访问非静态成员,也允许访问静态成员(如果你要访问其他类的静态成员, 前提是你要访问的成员必须被public出来)
5.什么时候用非静态?
----->静态成员只有在整个程序结束的时候才能够被释放资源。所以说,我们的程序中静态成员应该是越少越好。
6.静态构造函数不能加访问修饰符,静态构造函数会比实例构造函数先执行
代码如下(示例):
namespace 静态static
{
class Program
{
public static int age = 10;
static void Main(string[] args)
{
// Program pg = new Program();
Student student = new Student();
student.Name = "张三";
student.Age = 10;
student.SchoolName = "人大附中";
student.StudentSayHello();
----->静态字段/属性只能通过 :类名.成员名 来访问
----->静态成员 在类中只有一份 ,为类中多有对象所共有
// Student.zz;
----->静态类不能被实例化
// Persion p = new Persion();
----->静态方法也要通过类名来调用
Persion.PersionSayHello();
Console.ReadKey();
}
}
class Student
{
----->静态字段
public static int zz;
----->实例构造函数
public Student()
{
}
----->静态构造函数不能加访问修饰符,静态构造函数会比实例构造函数先执行
static Student()
{
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private int age;
public int Age
{
get { return age; }
set { age = value; }
}
private string schoolName;
public string SchoolName
{
get { return schoolName; }
set { schoolName = value; }
}
public void StudentSayHello()
{
Console.WriteLine("我叫{0},年龄{1},学校名称{2}",this.name,this.age,this.schoolName);
}
}
----->静态类中只能包含静态成员,不能包含实例成员
class Persion
{
private static int age;
public static int Age
{
get { return age; }
set { age = value; }
}
private static string name;
public static string Name
{
get { return name; }
set { name = value; }
}
public static void PersionSayHello()
{
Console.WriteLine("我是人类{0}",name);
}
}
}
二、继承
1.里氏转换原则以及is as运算符的基本使用
【@】里氏替换原则:
1.子类可以赋值给父类
2.如果父类中装的是子类对象,那么可以将这个父类转换为"对应"的子类对象
【@】我们可以使用is.as运算符帮助我们进行转换:
1.is、as都表示类型转换,不同的是,他们的返回值不一样。
2.is:是否可以执行类型转换 ,返回值是bool类型。
3.as:表示类型转换,如果成功,则返回对应的对象,如果失败则返回null。
注:对知识点进行补充—>//null “” string s=null string s="“这两个一个” "是在内存中开辟了控件,null一个是没有开辟内存空间
代码如下(示例):
namespace 里氏转换原则
{
class Program
{
static void Main(string[] args)
{
//开放封闭原则:对程序的扩展开放,对代码的修改保持封闭,了解即可
//子类可以赋值给父类类型的变量(前提是,这些都是在继承的基础上)
Student student = new Student();
Persion persion = student;//隐士转换
//Persion p = new Student();//也可以直接new
//---->如果父类中装的是子类对象,那么可以将这个父类转换为"对应"的子类对象
// Student s = (Student)p;
Console.WriteLine("转换成功");
//使用is 和 as关键字进行一个转换
Persion p = GetSingle(2);
#region 使用is执行转为
if (p != null)
{
if (p is Student)//表示p对象能够转换成Student
{
//如果返回值为true,则可以直接开始转换
Student stu = (Student)p;
stu.StudentSayHello();
}
else if(p is Teacher)
{
Teacher t = (Teacher)p;
t.TeacherSayHello();
}
}
else
{
Console.WriteLine("当前p为空");
}
#endregion
#region as转换
Teacher teach= p as Teacher;
if (teach != null)
{
teach.TeacherSayHello();
}
else
{
Console.WriteLine("当前t为null");
}
#endregion
Console.ReadKey();
}
static Persion GetSingle(int number)
{
Persion per = null;
switch (number)
{
case 1:
per = new Student();
break;
case 2:
per = new Teacher();
break;
default:
//如果传入的值与每一个case都不匹配,那么就直接执行default中的语句
break;
}
return per;
}
}
class Persion
{
}
class Student:Persion
{
public void StudentSayHello()
{
Console.WriteLine("我是学生,SayHello");
}
}
class Teacher : Persion
{
public void TeacherSayHello()
{
Console.WriteLine("我是老师");
}
}
}
二、多态
虽然多态是一个很抽象的问题,但是我对多态的理解如下:
1.多态意在让一个对象能够表现出多种的类型、状态。
2.多态:就是用父类类型变量,后面跟着子类的实例,然后可以调用子类的函数(这个就叫表现出多种类型,状态)。
3.实现多态的有三种方法:虚方法,抽象类,接口。
1.虚方法
虚方法的实现:
–>在父类的函数前面加个virtual关键字
—>在子类每个函数前面加上override关键字
代码如下(示例):
namespace 多态
{
class Program
{
static void Main(string[] args)
{
----->多态
----->封装、继承
----->多态意在让一个对象能够表现出多种的类型、状态
----->多态:就是用父类类型变量,后面跟着子类的实例,然后可以调用子类的函数(这个就叫表现出多种类型,状态)。
----->多态的好处:我们把不同的子类对象都当做父类来看,从而屏蔽子类之间的差异
----->写出通用的代码,做出通用的编程,以适应需求的不断改变。
----->实现多态的有三种方法:虚方法,抽象类,接口
----->虚方法的实现:
-->在父类的函数前面加个virtual关键字
--->在子类每个函数前面加上override关键字
Chinese c1 = new Chinese("张三");
Chinese c2 = new Chinese("李四");
Japanese j1 = new Japanese("松下电器");
Japanese j2 = new Japanese("渡边");
Korea k1 = new Korea("金秀贤");
Korea k2 = new Korea("全智贤");
American a1 = new American("科比布莱恩");
American a2=new American("奥巴马");
----->父类只能调用自己的成员,意思就是说父类类型的变量,存储的是子类的实例,但是也只能调用父类的成员,不能调用子类类型的成员
---->数组虽然是父类类型的,但是全部都是子类类型的对象
Persion[] pers = { c1,c2,j1,j2,k1,k2,a1,a2};
for (int i = 0; i < pers.Length; i++)
{
pers[i].SayHello();----->这里打出来的全是父类方法的值,父类只能调用自己的成员
----->如果能让父类表现出子类类型出来,就可以。(多态)
#region Old Method------这里是老方法
//if (pers[i] is Chinese)
//{
// ((Chinese)pers[i]).SayHello();
//}
//else if (pers[i] is Japanese)
//{
// ((Japanese)pers[i]).SayHello();
//}
//else if (pers[i] is Korea)
//{
// ((Korea)pers[i]).SayHello();
//}
//else if (pers[i] is American)
//{
// ((American)pers[i]).SayHello();
//}
#endregion
}
Console.ReadKey();
}
}
class Persion
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
public Persion(string name)
{
this.Name = name;
}
----->标记这个函数是虚函数,可以被子类重写。
public virtual void SayHello()
{
Console.WriteLine("我是人类");
}
}
class Chinese:Persion
{
public Chinese(string name) : base(name)----->父类重写了构造函数,把无参的构造函数干掉了,所以要显式的调用父类有参的构造函数
{
}
public override void SayHello()
{
Console.WriteLine("我叫{0},我是中国人",this.Name);
}
}
class Japanese : Persion
{
public Japanese(string name) : base(name)
{
}
----->override表示重写父类的虚函数
public override void SayHello()
{
Console.WriteLine("我叫{0},我是日本人",this.Name);
}
}
class Korea:Persion
{
public Korea(string name):base(name)
{
}
public override void SayHello()
{
Console.WriteLine("我叫{0},我是韩国人",this.Name);
}
}
class American : Persion
{
public American(string name):base(name)
{
}
public override void SayHello()
{
Console.WriteLine("我叫{0},我是美国人",this.Name);
}
}
}
2.抽象类
1.抽象类需要abstract关键字来修饰
2.里面可以包含抽象成员,也可以包含普通成员,代码中有详细的概括
代码如下(示例):
namespace 抽象类
{
class Program
{
static void Main(string[] args)
{
Animal a = new Dog();
Dog d = new Dog();
-->如果父类中的函数你知道怎么写(方法内有具体的实现),用虚方法实现多态
-->反之,使用抽象类来实现多态(方法内没有具体实现)
-->抽象类特点:
-->1、子类如果继承了一个抽象的父类,那么这个子类必须将抽象父类中的所有成员重写。(除非这个子类也是抽象类)
-->2、抽象类中除了有抽象成员外,还可以有普通的成员,继承那一套抽象类同样可以使用
-->3、子类重写的父类抽象的函数,必须跟父类的抽象函数具有相同的方法签名(相同的参数和相同的返回值)
}
}
abstract class Animal
{
-->当前这个函数 是抽象函数
-->当父类不知道子类如何实现的时候,可以将父类提供的函数标记为抽象函数
-->抽象函数,必须存在于抽象类中
public abstract string Bark();
#region 抽象类中的非抽象成员
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private int age;
public int Age
{
get { return age; }
set { age = value; }
}
private char gender;
public char Gender
{
get { return gender; }
set { gender = value; }
}
public void SayHello()
{
Console.WriteLine("我是抽象类");
}
#endregion
}
class Cat : Animal
{
-->重写抽象类中的抽象方法子类仍然需要用override关键字
public override string Bark()
{
Console.WriteLine("猫咪喵喵叫");
return "123";
}
}
class Dog : Animal
{
public override string Bark()
{
Console.WriteLine("狗狗汪汪叫");
return "123";
}
}
}
3.接口
1.接口概念:接口侧重于表示 1、能力 2、规范
2.接口的名字一般都以"I"开头,侧重于表示一种能力
3.接口可以多继承
4.接口中的成员不写访问修饰符,默认是public,而类中的成员不写访问修饰符,默认是private
5.接口的名字一般都以"I"开头,侧重于表示一种能力
6.接口实现多态和抽象类实现多态是一样的,都是声明父类去指向子类对象…
代码如下(示例):
namespace 接口
{
class Program
{
static void Main(string[] args)
{
--->接口概念:接口就表示 1、能力 2、规范
--->实现多态
--->接口实现多态和抽象类实现多态是一样的,都是声明父类去指向子类对象
IKouLan i = new Student();
i.KouLan();
IFly i2 = new Student();
i2.Fly();
Console.ReadKey();
--->在什么情况下用虚方法,抽象类,接口
--->基类有具体实现用虚方法。
---->基类没有具体实现,用抽象类,如果有子类不需要实现的,偏向于侧重于一种规范的就使用接口。
}
}
--->为了满足Student的多继承,我们使用接口
--->接口的名字一般都以"I"开头,侧重于表示一种能力
--->接口可以多继承
interface IKouLan
{
--->类中的成员不写访问修饰符,默认是private
--->而接口中的成员不写访问修饰符,默认是public
--->不允许添加访问修饰符
void KouLan();
}
interface IFly
{
void Fly();
}
class Persion
{
public void CHLSS()
{
Console.WriteLine("我是人类");
}
--->不能再父类中封装扣篮的函数,因为并不是所有的子类都会扣篮
//public void KouLan()
//{
// Console.WriteLine("NBA球员能够扣篮");
//}
}
class Student : Persion, IKouLan, IFly
{
public void Fly()
{
Console.WriteLine("学生可以飞");
}
public void KouLan()
{
Console.WriteLine("学生会扣篮");
}
}
class Teacher : Persion, IKouLan
{
public void KouLan()
{
Console.WriteLine("老师也会扣篮");
}
}
class NoLegs : Persion
{ }
class NBAPlay : IKouLan
{
public void KouLan()
{
Console.WriteLine("NBA球员会扣篮");
}
}
}
3.接口的特点
1.接口中的成员不能加“访问修饰符”,接口中的成员访问修饰符为public,不能修改。
2.类中的成员默认的访问修饰符是private ,而接口中默认的访问修饰符是public
3.接口中的成员不能有任何实现(“光说不做”,只是定义了一组未实现的成员)。
4.接口中只能有方法、属性、索引器、事件,不能有“字段”和构造函数。
5.接口与接口之间可以继承
6.接口并不能去继承一个类,而类可以继承接口 (接口只能继承于接口,而类既可以继承接口,也可以继承类)
7.实现接口的子类必须实现该接口的全部成员。
8.一个类可以同时继承一个类并实现多个接口,如果一个子类同时继承了父类A,并实现了接口IA,那么语法上A必须写在IA的前面。
注:当一个抽象类实现接口的时候,需要子类去实现接口。
总结
多写写多看看得到的总会多一点。