继承以后子类可以得到什么:
- 子类拥有父类非private的属性和方法
- 子类可以添加自己的方法和属性,即对父类进行扩展
- 子类可以重新定义父类的方法,即多态里面的覆盖,后面会详述
关于构造函数:
- 构造函数不能被继承,子类可以通过(Java super()/(C# base())显示调用父类的构造函数
- 创建子类时,编译器会自动调用父类的 无参构造函数
- 如果父类没有定义无参构造函数,子类必须在构造函数的第一行代码使用super()/base()显示调用
构造器的总结:一个子类继承父类,那么在调用构造器时,会先调用父类的构造器,这个父类的构造器和子类中的要一样,如果在父类中没有写和子类一样的构造器,那么必须在子类中用base声明调用父类其他的构造器,否则会报错。构造器的一个原则就是:在调用子类构造器之前必须先调用父类的构造器,如果父类中有和子类一样的构造器,那么不用再写什么,如果没有,那么必须声明在调用子类构造器之前要调用哪一个父类的哪一个构造器,用base声明。例如:
class Person
{
protected String name;
protected int age;
protected String sex;
public Person()
{
Console.WriteLine("Person Constructor");
}
public Person(String name)
{
Console.WriteLine("Person Constrctor-----" + name);
}
}
class Husband :Person
{
public Husband()
{
Console.WriteLine("Husband Construct!");
}
}
上面的例子在父类中有相同的构造器,那么不需要用base声明,如果没有则要用base显示声明去调用哪一个父类构造器:
class Person
{
protected String name;
protected int age;
protected String sex;
public Person(String name)
{
Console.WriteLine("Person Constrctor-----" + name);
}
}
class Husband :Person
{
public Husband():<span style="color:#ff0000;">base("cherry")
</span> {
Console.WriteLine("Husband Construct!");
}
}
上面的例子在父类中没有无参构造器,所以在子类中用base显示声明调用父类的一个参数的构造器。
一个原则:在调用子类构造器之前必须先调用父类的构造器。
向上转型也就是说的多态的操作。
父类中一般将需要继承到子类中的属性和字段一般设置为protected。
综上所述,使用继承确实有许多的优点,除了将所有子类的共同属性放入父类,实现代码共享,避免重复外,还可以使得修改扩展继承而来的实现比较简单。
首先我们需要明确,继承存在如下缺陷:
1、父类变,子类就必须变。
2、继承破坏了封装,对于父类而言,它的实现细节对与子类来说都是透明的。
3、继承是一种强耦合关系。
多态的总结概括:
- 当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法,但是它仍然要根据继承链中方法调用的优先级来确认方法,该优先级为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。这里的this原文作者理解为引用变量的类型,自己理解为实际的对象类型,这并不影响判断的正确性,如果理解为引用变量的类型,那么在最后还是要向下转型成为真正的对象的类型。
- 上面的结论在C#和Java中是一样的,并且优先级顺序也是一样的。不相同的是C# 和Java的语法不一样,C# 中需要使用virtual和override来声明虚方法和重写的方法,不然编译器不会认为是多态的体现,而在Java中则不需要使用。
- 上面红字部分的意思很重要,这是向上转型的多态中最重要的体现:被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的。如果这个方法在引用对象的类型中重写了,那么就是这调用这个方法,如果没有,那么则调用父类中的方法。例如:
A a2 = new B();
Console.WriteLine(a2.show(b));
class B:A
{
public string show(B obj)
{
return ("B and B");
}
public override string show(A obj)
{
return ("B and A");
}
}
输出的是“B and A” 而不是“B and B”
如果想要调用类B中的show(B obj) 方法,那么直接使用B的对象,不用向上转型,如果转型了那么再强制类型转换成B就可以了。