1.继承的概念
继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
继承可以解决代码复用的问题,极大的提高代码的简洁性✌
2.继承原理图
3.类的继承格式
在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下:
class 父类 { } class 子类 extends 父类 { }
接下演示一个继承的实例:
我们先写一个父类:
/** * 三大特性:继承演示的父类 */ public class Inherit { // 共有的属性 public String name; public int age; private double score; // 共有的方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public double getScore() { return score; } public void setScore(double score) { this.score = score; } public void showInfo() { System.out.println("学生姓名:" + name + " 年龄:" + age + " 成绩:" + score); } }
写一个小学生类继承这个父类:
/** * 小学生,继承父类的子类 */ public class Pupil extends Inherit { // 小学生独有的方法 public void say() { System.out.println("爱你孤身走暗巷~"); } }
再写一个大学生继承这个父类:
/** * 大学生,继承父类的子类 */ public class Graduate extends Inherit { public void say() { System.out.println("我是大学生,我叫:" + name); } }
测试类:
/** * 继承演示的测试类 */ public class InheritTest { public static void main(String[] args) { Pupil pupil = new Pupil(); pupil.setName("王强"); pupil.setAge(12); pupil.setScore(100); pupil.say(); // 爱你孤身走暗巷~ pupil.showInfo(); // 学生姓名:王强 年龄:12 成绩:100.0 Graduate graduate = new Graduate(); graduate.setName("大河"); graduate.setAge(22); graduate.setScore(60); graduate.say(); // 我是大学生,我叫:大河 graduate.showInfo(); // 学生姓名:大河 年龄:22 成绩:60.0 } }
4.继承的小细节
私有属性和方法的继承:
私有属性和方法不能在子类直接访问,要通过公共的方法去访问
上述程序中,我们对score属性做了private的访问修饰,随后发现在子类无法访问这个属性,那么应该怎么做呢?🐱🐉
可以看到,我们通过封装完美解决了这个问题,而封装的方法的访问权限应该设置为public✨
子类必须首先调用父类的构造器,完成对父类的初始化:
我们的父类:
// 父类的无参构造 public Inherit() { System.out.println("父类的无参构造执行~"); }
我们的子类:
// 子类的无参构造 public Pupil() { System.out.println("子类的无参构造执行~"); }
当我们新建子类的对象时,会输出如下:(首先初始化父类的构造器,再初始化子类的构造器)
父类的无参构造执行~ 子类的无参构造执行~
需要说明的是,默认情况下总会去调用父类的无参构造器,如果父类没有提供一个无参构造器,则必须在子类使用super指定父类的构造器,否则会发生一个错误!❌
如果希望指定去调用父类的某个构造器,则显式的调用以下,使用super关键字
super在使用时,必须放在构造器的第一行,this也是同样的,所以他们不能共存使用
另外,java中所有的类都是Object的子类:👴🏻
需要注意的是 Java 不支持多继承,但支持多重继承:
5.继承的本质
现在我们来分析如下的代码块:
加载类的时候,首先会加载Object类(祖宗类),随后加载GrandPa类 - Father类 - Son类
随后会创建对象的堆空间,并在堆中分配空间,首先并分配GrandPa的属性
分配Father的属性,虽然和GrandPa的属性有冲突💥,但是java会选择开辟一个新的空间存放
分配Son的属性,同Father
返回堆中的地址给son
现在我们再来看,如果执行了下面的这行代码,它会输出什么信息呢?
System.out.println(son.name);
这时候就需要按照查找关系来返回信息啦!就近原则
🚀
综合上述,显然它会输出:大头儿子
谨记:当属性按照就近原则向上查找时,一旦遇到一个不能访问的错误(存在该属性但是权限不不够),就会停止查找,产生一个编译错误🤳