目录
继承extends
继承就是通过扩展一个类来建立另外一个类的过程。
extends:表明正在构造的新类派生于一个已存在的类。(父亲对儿子开放的东西,儿子就算自己没有也能用,这就是继承。)
子类拥有比父类更加丰富的功能,是因为子类会自动继承超类的方法和域。
public class extend {
public static void main(String[] args) {
new zi(); //运行结果:打印fu
}
}
class fu {
public String name="fu";
}
class zi extends fu{
zi(){
System.out.println(name);
}
}
覆盖方法Override
父亲对儿子开放,但是时代变了,父亲那套在儿子这里不适用,儿子需要因地制宜的改动父亲的东西,这就是覆盖。
例如:父的年龄=40,子的年龄=父的-25,方法名都是getAge。(也体现了父的属性可以直接给子用的特点:zi没有age属性,但方法里直接使用了age属性,其age是fu的)
public class extend {
public static void main(String[] args) {
zi zi=new zi();
System.out.println(zi.getAge()); //15
}
}
class fu {
public int age=40;
public int getAge() {
return age;
}
}
class zi extends fu{
public int getAge() {
return age-25;
}
}
注意点:
1、子类无法直接访问超类的私有域,若一定要访问,需要使用公用接口,而单纯使用公用接口,有可能会因为覆写的问题,重复调用自身,所以需要super关键字来帮忙。
例:现在不是父了, 而是母,母亲的年龄不想让别人知道,这个时候就不能直接访问母亲年龄
(母亲年龄不对子开放,子无法接访问)
(与上面代码只改红框处(类名无所谓,不划出))
super和this
this:1、引用隐式参数。2、调用该类其他的构造器。
super:1、调用超类的方法。2、调用超类的构造器。
调用构造器的语句只能作为另一个构造器的第一条语句出现(所以this和super只能二选一)
构造参数可以传递给本类(this)的其他构造器,也可以传递给超类(super)的构造器。
2、子类中可以增加域,增加方法或覆盖超类的方法,但绝对不能删除继承的任何域和方法
子类实例初始化过程
public class extend {
public static void main(String[] args) {
new zi();//运行结果: 打印 fu zi
}
}
class fu {
fu(){
System.out.print("fu ");
}
}
class zi extends fu{
zi(){
//super();调用父类中空参数的构造函数
System.out.print("zi");
}
}
为什么会有这种结果呢?
因为super,在子类的构造器里,有一句默认的隐含语句: super(); 子类的构造器里写不写,都会默认有这句
前面提到,super的作用之一激就是调用超类的构造器 。
结论:子类的实例化过程------子类的所有构造函数都会默认访问父类的构造函数
为什么要有这种结果呢?
子类继承了父类,有时候直接在构造函数里使用了父类的属性。如果没有super,在实例化子类时若使用到了父类属性,而此时父类没有实例化时,子类上哪找要用的东西呢? 这也是为什么super语句必须放在第一行的原因。
若父类没有空参构造函数,则子类的构造函数必须明确说明super到哪个构造函数。
例如:
class fu {
fu(int x){
System.out.print("fu ");
}
}
class zi extends fu{
zi(){
super(3);
//super();调用父类中空参数的构造函数
System.out.print("zi");
}
}
结论:子类的初始化必须有父类的帮助----构造器
初始化顺序
- 子类构造器先入栈,默认初始化
- Super 去了父类构造器,父类构造器入栈。父类构造器中若有方法被覆写,则回去运行子类方法。父类构造器初始化完毕后出栈。(相当于运行完super()语句)
- 子类显式初始化
- 构造代码块初始化
- 子类构造器中的方法
(super的父类构造器里有个show方法,运行时发现被子类覆写,则执行子类show方法,此时尚未显示初始化,故num为默认0)