目录
一、子类到底能继承父类中的哪些内容?
二、继承内存图
三、继承中:成员变量和成员方法的访问特点
(一)成员变量的访问特点
(二)成员方法的访问特点
1.this与super访问成员方法的特点
2.方法重写
2.1方法重写的本质:子类覆盖了从父类继承的虚方法表里的方法。
2.2方法重写注意事项和要求
四、继承中:构造方法的访问特点
五、super与this关键字
一、子类到底能继承父类中的哪些内容?
父类中的构造方法:无论是不是私有的,子类都无法继承,因为违背了构造方法必须与类名一致的原则。
父类中的成员变量:无论父类的成员变量是不是私有的,子类都能继承,但是父类私有的成员变量,子类无法直接使用,如果必须要使用,父类就必须要提供setXxx和getXxx方法。
父类中的成员方法:子类可以继承父类的虚方法表中的成员方法,子类无法继承父类中不在虚方法表中的成员方法。
虚方法表:将类中可能经常被使用的方法抽取到虚方法表中,抽取到虚方法表中的方法要满足以下条件:非private、static和final修饰
如下图所示:C类将自己的虚方法表交给子类B,子类B会根据虚方法表中的内容,在C的基础上再添加自己类中的虚方法;A类同上。
子类在调用方法时,会查看方法区中,该方法是不是虚方法。并且是先在子类的虚方法表中查找,子类中没有找到,再去父类的虚方法表中查找,以此类推。
二、继承内存图
Fu类和Zi类因为是继承的关系,在方法区中加载的时候,Fu类和Zi类都会被加载。并且会在堆中开辟一块空间,这块空间分成两份,一份存放父类的属性,另一份存放子类的属性。在对属性进行赋值时,先去子类中寻找是否有该属性,子类中没有找到,再去父类中寻找,找到为止。
三、继承中:成员变量和成员方法的访问特点
(一)成员变量的访问特点
就近原则:谁离得近就用谁
(二)成员方法的访问特点
1.this与super访问成员方法的特点
this是先在本类中找,本类没有再去父类中找;
super是先在父类中找,父类中没有再去更高一层的父类中找。
2.方法重写
2.1方法重写的本质:子类覆盖了从父类继承的虚方法表里的方法。
调用时是在虚方法表中查找。
2.2方法重写注意事项和要求
当父类中的方法不能满足需求,就需要进行重写。重写有的时候仍然会用到父类,使用super.方法体+子类新增的代码即可;当不需要父类的内容时,直接写子类新增的代码即可。
- 重写方法的名称、形参列表必须与父类中的一致。
- 子类重写父类方法时,访问权限子类必须大于等于父类
- 子类重写父类方法时,返回值类型子类必须小于等于父类
- 建议:重写的方法尽量和父类保持一致
- 只有被添加到虚方法表中的方法才能被重写
四、继承中:构造方法的访问特点
- 特点1:父类中的构造方法不会被子类继承。
- 特点2:子类中所有的构造方法默认先访问父类中的无参构造,再执行自己。
原因:
- 子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据
- 子类初始化之前,一定要调用父类构造方法,先完成父类数据空间的初始化。
子类调用父类构造方法的方式:
- 子类构造方法的第一行语句默认都是:super(),不写也存在,且必须在有效代码的第一行
- 如果想调用父类有参构造,必须手动写super进行调用
五、super与this关键字
我们知道,在构造方法中,会默认有一个super(),调用父类的无参构造。现在有一个需求:在创建对象的时候,调用无参构造时,直接给某个属性赋值。
代码如下:
public class TestDemo {
public static void main(String[] args) {
Student student = new Student();
System.out.println(student.school); // 北京大学
}
}
class Student {
String name;
int age;
String school;
public Student() {
// 调用无参构造时,给属性默认值
this(null, 0, "北京大学");
}
public Student(String name, int age, String school) {
this.name = name;
this.age = age;
this.school = school;
}
}
小细节:
上述代码中,在无参构造中可以用this(),调用本类的有参构造,并给出默认值;
且因为super和this不能在一个构造方法中同时使用,这里写了this,super就不会被虚拟机添加了。