黑马程序员--里氏转换
?如果有一个非静态类,当我们在线程栈你创建了引用变量,但没有使用new方法创建对象时,该引用变量可以使用点运算符点出类的成员吗
答案是:经调试发现是可以的
说明:变量类型决定可以点出的什么成员,(专业术语来说,就是引用变量决定指针偏移量).但是,若要给点出的成员赋值或者使用它,必须使用new创建对象,以给它分配内存
里氏转换
■子类对象可以无条件的赋值给父类: 父类类型名 引用变量名=new 子类对象();如base b=new sub();
■若一个父类的引用变量指向一子之类对象,那么可以父类引用变量强制赋强制转化为子类赋值给子类变量.sub s=(sub)b;
( 概括:一个父类引用可以指向一个子类对象,但一个子类引用不能指向一个父类对象.因为子类的指针偏移量较父类要大,好比将一个long类型的大数(子类引用变量)放在一个int类型的内存空间(父类对象),这样肯定会出错.
通俗的解释就是:引用变量好比标签,动物类派生出一个狗类,狗对象贴动物标签可以,但是一个具体的动物贴个狗标签是不合理的.)
为什么说子类的引用指针偏移量要打呢?因为子类的引用不仅可以点出父类的成员,还能点出自己的附加成员.
引用类型与值类型有点不一样,值类型是变量分配内存空间,引用类型是new()分配内存空间,引用类型的引用变量好比值类型的数值,如下
long big=320000000000000000000000000000; int little=32;
big=32;// 对 little=3200000000000000000000000000000000000000; //错
new sub()=b base; //对 new base()=s sub //错
以上理解为new sub()相对于long类型变量这个大空间(指针偏移量大),大空间能装的下这个b小数
new base()为这个相对于int类型变量这个小空间,小空间装不了s这个大数
public class Person//基类,或称为父类 { 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 Person()//建议只要自己声明了无参构造方法,务必再声明一个无参构造方法.系统默认会调用无参构造方法 { Console.WriteLine("我是父类"); } public Person(string name, int age, char gender):this() { this.Name = name; this.Age = age; this.Gender = gender; } public void Say() { Console.WriteLine("我是{0},我今年{1}岁了,我是{2}生", name, age, gender); } }
public class Teacher:Person//继承类,或称子类 { private string course; public string Cource { set{course=value;} get{return course;} } private int yearsOfService; public int YearsOfService { set { yearsOfService = value; } get { return yearsOfService; } } public void SayHello() { Console.WriteLine("你们好,我是{0},我今年{1}岁了,教书{2}年了,我是{3}老师", Name, Age, yearsOfService, course); } public Teacher(string name,int age,char gender,string course,int yearsOfService):base( name, age, gender) //此处若没写base(name,age,gender)构造方法,便是默认调用Person的无参构造方法即base() { this.course = course; this.yearsOfService = yearsOfService; } }
public class Student : Person//继承类Student { private int classId; public int ClassId { set { classId = value; } get { return classId; } } private string hobby; public string Hobby { set { hobby = value; } get { return hobby; } } public void SayHello() { Console.WriteLine("大家好,我是{0},我今年{1}岁了,我是{2}生,我是{3}班的,我喜欢{4}", Name, Age, Gender, classId, hobby);//包含基类的成员,加自己的成员,除了基类的私有成员外,其余成员都能访问到 } public Student(string name,int age,char gender,int classId,string hobby):base(name,age,gender)//父类构造方法执行之后才执行 { this.hobby = hobby; this.classId = classId; } }
class Program { static void Main(string[] args) { //依次做自我介绍 Person[] ps = new Person[]{ new Teacher("翟群",23,'女',"c#",0), new Student("何雄军",24,'男',2,"计算机"), new Person("呵呵",23,'女') }; //使用基类的引用访问不到子类的成员,所以要进行里氏转换,以访问到子类的成员 for (int i = 0; i < ps.Length; i++) { if (ps[i] is Teacher)//判断是否为Teacher类型对象 { ((Teacher)ps[i]).SayHello(); //结果:你们好,我是翟群,我今年23岁了,,我教书0年了,我是c#老师 } else if (ps[i] is Student) { ((Student)ps[i]).SayHello(); //结果: 大家好,我是何雄军,我今年24岁了,我是男生,我是2班的,我喜欢计算机 } else { ps[i].Say(); //结果:我是呵呵,我今年23岁了,我是女生. } } //Teacher t = (Teacher)ps[2]; // Teacher t = ps[2] as Teacher; as转换符等同与以下 Teacher t = ps[2] is Teacher ? ((Teacher)ps[2]) : null; Console.ReadKey(); }