一、概述
1.定义:
面向对象三大特征之一,可以把多个子类中重复的代码抽取到父类中,子类可以使用,减少代码冗余,提高代码的复用性
2.特点:
①子类可以得到父类的属性和行为,子类可以使用。
②子类可以在父类的基础之上新增其他功能,子类更强大。
③java只支持单继承:一个类只能继承一个直接父类。不支持多继承,但支持多层继承
④java中所有的类都直接或间接的继承于Object类。(Object类是java中所有类的祖先)
⑤子类可以访问父类中非私有的成员。(注意:访问 ≠ 继承)
继承:父类中的成员,子类可以拷贝一份过来,相当于子类也有。但有些时候,子类虽然拿过来了,但不一定能够调用/访问。
3.使用场景:
当类与类之间,存在相同(共性)的内容,并满足子类是父类的一种,就可以考虑使用继承,来优化代码。
二、继承内容
1.构造方法
父类的构造方法不能被子类继承,子类构造方法需要手动重新创建
构造方法的方法名是要和类名一致的,如果继承了父类的构造方法,那就会发生冲突。
2.成员变量
成员变量不管是私有的还是非私有的,在子类中都是可以继承下来的。只不过,私有的虽然继承下来了,但是不能直接去使用。
注:
①子类在加载字节码文件时,会把父类的字节码文件一同加载到方法区当中。
②在创建对象时,会有一部分空间存储从父类继承下来的成员变量,还有一部分是自己的成员变量
非私有:
私有:
访问 ≠ 继承
父类成员变量私有时,子类也能够继承下来,在堆中其内存空间中也存放着父类的私有成员变量。但由于私有,无法直接访问,会报错。如果要用,需要使用对应的get和set方法。
3.成员方法
如果该成员方法是虚方法,则能被子类继承下来,否则不能。
虚方法:非private,非static,非final修饰的成员方法
java会从最高的父类(Object类)开始,依次抽取虚方法放入虚方法表中,然后继承给下一个子类。子类在该基础上,继续抽取,再继承给下一个子类。
访问 ≠ 继承
Demo1:不能访问也不能继承
在Object类中有5个虚方法,继承给Fu后,加上fushow1一共6个虚方法。再继承给Zi,加上zishow一共七个虚方法,所以Zi类的虚方法表长度为7。
fushow1和zishow由于是虚方法,会直接去Zi类的虚方法表中查找。
由于fushow2是private修饰,是非虚方法,不能继承,调用时不会去Zi类的虚方法表中找,而去所有的成员方法中找,找不到再去Fu类的所有成员方法中找。这时发现是private修饰,不能够访问,报错。
Demo2:可以访问但不能继承
class Fu{
public void fushow1(){
System.out.println("public-------fushow1");
}
public static void fushow2(){
System.out.println("static-------fushow2");
}
}
class Zi extends Fu{
public void zishow(){
System.out.println("public-------zishow");
}
}
public class Test {
public static void main(String[] args) {
Zi z= new Zi();
z.zishow();
z.fushow1();
z.fushow2();
}
}
运行结果:
fushow2不是虚方法,不能添加到虚方法表中,也就不能继承
但子类发现不是虚方法之后,就不会去虚方法表中找。先去子类自己的所有成员方法中找,没找到再去父类,最后发现是public修饰,可以访问。
三、this与super关键字
1.就近原则
继承中,成员变量的访问特点:就近原则
class Fu{
String name="fu";
String school="DHU";
}
class Zi extends Fu{
String name="zi";
public void zishow(){
String name="zishow";
System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);
System.out.println("-----------------");
System.out.println(school);
System.out.println(this.school);
System.out.println(super.school);
}
}
public class Test {
public static void main(String[] args) {
Zi z=new Zi();
z.zishow();
}
}
运行结果:
不加this和super,会先在函数的局部变量里面找,没有再往上找。
this代表方法调用者的地址值,也就是再本类的成员变量里面找,如果没有再往上找。
super表示父类,会去父类的成员变量中找,如果没有再往上找
2.方法重写
在继承体系中,子类出现了和父类一模一样的方法声明,就就称子类的这个方法是重写的方法。
应用场景:当父类的方法不能满足子类现在的需求时,需要进行方法重写
格式:加上@Override重写注解(虽然不加也可以,但是加了可以校验重写是否正确,同时可读性好,所以建议加上)
本质:覆盖虚方法表中的方法。(只有被添加到虚方法表中的方法才能被重写)
注意事项:
①重写方法的名称、形参列表必须与父类中的一致
②子类重写父类方法,访问权限必须大于等于父类
③子类重写方法时,返回值类型必须小于等于父类(先了解)
// 父类
class SuperClass{
public People create(){
return new People();
}
}
// 子类
class SubClass extends SuperClass{
@Override
public Student create(){
return new Student();
}
}
class People{
}
class Student extends People{
}
建议:重写的方法尽量和父类保持一致
④只有被添加到虚方法表中的方法才能被重写
四、继承中的构造方法
1.访问特点:
①父类的构造方法不会被子类所继承
②子类中所有的构造方法默认先访问父类的无参构造,在执行自己
2.原因:
子类在初始化的时候,有可能会用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据。
注:子类初始化之前,一定要调用父类构造方法先完成父类数据空间的初始化。
3.调用方法
子类构造方法的第一行语句默认都是:super(): 不写也隐含在内,且必须在第一行。
如果想调用父类的有参构造,必须手动写super进行调用
4.this和super的使用
this:本质就是一个局部变量,表示当前方法调用者的地址值
super:表示父类存储空间
对于this访问构造方法,举个🌰🌰🌰
需求:对于没有明确给定学校名的学生,创建时默认为“清华大学”
class Student{
String name;
int age;
String school;
public Student(){
//super(); 报错
//System.out.println("aaa"); 报错
this(null,0,"清华大学");
System.out.println("aaa");
}
public Student(String name, int age, String school) {
super();
this.name = name;
this.age = age;
this.school = school;
}
}
public class Test {
public static void main(String[] args) {
Student s=new Student();
}
}
在Student类的无参构造中用this调用了本类的其他构造方法,
注意:当调用了本类其他构造方法,虚拟机就不会再在第一行添加super();
因为在其他构造方法的第一行,已经隐含了一个super(); 只要有一个super访问父类即可。
所以在this调用其他构造方法的语句前,不能加其他任何语句,只能在该语句后面加。
super访问父类构造方法(员工类与经理类)