
目录
什么是继承呐?我们先看一下图片:
图片反映了教师和学生都属于人这一类,他们也有自己的共性。
任课教师和教辅人员都属于教师,也同时都属于人这一类;
本科生和研究生都属于学生,也同时都属于人这一类。
就好比教师是任课教师和教辅人员的父类,学生是本科生和研究生的父类。而教师和学生属于人的子类。
父类通用,子类具体。子类具有父类的一般特征也具有自身特性。
强调:共性抽取,实现代码复用,这就是继承的目的。
关键字extends 继承的语法格式也很简单:
修饰符 class 子类(派生类) extends 父类(基类/超类){
//
}
下面我们来实现一下 共性抽取,写出派生类。
- /**
- * @author Sun
- * @version 2021.2
- * @date 2022/5/19 11:20
- */
- class Person {
- public String name;
- public int age;
- public void school() {
- System.out.println(name+"正在学校!");
- }
-
- }
- class Student extends Person {
- public int studentid;
-
- public void study() {
- System.out.println("我是学生,我在学习!");
- }
-
- }
- class Teacher extends Person {
- public int workid;
-
- public void teach() {
- System.out.println("我是老师,我在备课!");
- }
- }
强调:
(1)子类继承父类,会将父类的成员方法或成员变量都继承到自己身上;
(2)子类继承父类,子类必须新添加自己特有的成员,体现出和父类的相同,不然子类和父类相同了,那要继承就没有意义。
问题:
🐲(1)在子类中,如何访问父类的成员变量
🐲(2)在子类中,如何访问父类的成员方法
这种访问,非常简单:
- package 继承;
-
- /**
- * @author Sun
- * @version 2021.2
- * @date 2022/5/19 11:37
- */
- class Father {
- public int a=1;
- public int b=2;
- }
- class child extends Father {
- public int c=3;
- public int d=4;
- public void test() {
- System.out.println(this.a);
- System.out.println(this.b);
- System.out.println(this.c);
- System.out.println(this.d);
- }
- }
- public class Test {
- public static void main(String[] args) {
- child child = new child();
- child.test();
- }
- }

this.成员变量


相信大家也已经看明白了,如果子类非要访问父类同名成员,那就得使用super关键字
super关键字表示子类从父类中继承的这一部分成员的地址
总结: 子类访问父类成员变量
🟥(1)如果子类中有,优先访问自己的成员变量
🟩(2)如果子类中没有,就从父类中继承下来,如果父类中也没有,那就报错了
🟧(3)如果有成员变量同名,那就优先访问子类自己的
一句话,那就是:
🟪成员变量访问遵循就近原则,先访问自己,如果没有,找父类
- class Base{
- public int a=1;
- public int b=2;
-
- public void methodA() {
- System.out.println("Base::methodA()");
- }
- }
- class Derived extends Base {
- public int a=3;
- public int d=4;
-
- public void methodB() {
- System.out.println("Derived::methodB()");
- }
- public void test(){
- methodA();//访问父类继承的methodA()
- methodB();//访问字类自己的methodB()
- }
- }
- public class Test02 {
- public static void main(String[] args) {
- Derived derived = new Derived();
- derived.test();
- }
- }
- package 继承;
-
- /**
- * @author Sun
- * @version 2021.2
- * @date 2022/5/19 11:53
- */
- class Base{
- public int a=1;
- public int b=2;
-
- public void methodA() {
- System.out.println("Base::methodA()");
- }
- public void methodB() {
- System.out.println("Base::methodB()");
- }
- }
- class Derived extends Base {
- public int a=3;
- public int d=4;
-
- public void methodA(int val) {
- System.out.println("Derived::methodA(int)"+val);
- }
- public void methodB() {
- System.out.println("Derived::methodB()");
- }
- public void test(){
- methodA();//Base::methodA()
- methodA(100);//Derived::methodA(int)
- methodB();//Derived::methodB(int)
- }
- }
- public class TestDemo {
- public static void main(String[] args) {
- Derived derived = new Derived();
- derived.test();
- }
- }
通过代码,我们可以看出:
如果子类和父类的同名方法中,构成了重载,也就是同名但参数列表不同时,就可以根据自己的参数用合适的方法进行访问
如果子类方法和父类同名方法中,没有构成重载,那就是重写。就还是优先访问子类自己的方法。
如果非要访问父类的同名成员方法, super.同名方法 就可以实现了。
- package 继承;
-
- /**
- * @author Sun
- * @version 2021.2
- * @date 2022/5/19 11:53
- */
- class Base{
- public int a=1;
- public int b=2;
-
- public void methodA() {
- System.out.println("Base::methodA()");
- }
- public void methodB() {
- System.out.println("Base::methodB()");
- }
- }
- class Derived extends Base {
- public int a=3;
- public int d=4;
-
- public void methodA(int val) {
- System.out.println("Derived::methodA(int)"+val);
- }
- public void methodB() {
- System.out.println("Derived::methodB()");
- }
- public void test(){
- methodA();//Base::methodA()
- methodA(100);//Derived::methodA(int)
- super.methodB();//Base::methodB()
- }
- }
- public class TestDemo {
- public static void main(String[] args) {
- Derived derived = new Derived();
- derived.test();
- }
- }
总结:
(1) 如果自雷中有,优先访问自己的成员方法
(2)如果子类中没有,就从父类中继承;如果父类中也没有,那就报错
(3) 如果有成员方法同名,并构成重载,就可以根据自己的参数,选择合适的方法访问
(4) 如果有成员方法同名,但没有构成重载,如果直接访问成员方法就会访问子类自己的
(5) 如果有成员方法同名,但有没构成重载,那就直接 super.同名方法 ,才可以访问父类成员方法
成员变量访问原则 : 先自己,自己没有,找父类。
前面我们已经使用了super关键字了,下面我们来了解一下super的其他作用:
作用:在子类方法中访问父类的成员
super关键字只能在非静态的方法中使用:
Because : 静态方法 不依赖对象
super 从父类中访问成员对象
两个矛盾,不能同时存在。
super() 调用父类的构造方法
来初始化子类继承过来父类的属性。
| 相同点 | (1)在构造方法中调用,必须是构造方法中的的语句,并且super和this不能同时存在 (2)只能在静态方法中使用,两个都需要对象 (3)都是关键字 |
| 不同点 | (1)this是当前对象的引用,super是子类对象从父类继承下来的成员的引用 (2)在构造方法中一定会存在super()的调用,不管写不写都有,this()是如果不写就没有 (3) this()用于调用自己类的构造方法 super()用于调用父类的构造方法,两个不能同时使用 (4) 在静态的成员方法中,this是用来访问本类的方法和属性,super用来访问从父类继承下来的属性 |
子类对象的构造方法就是由父类继承下来的构造方法+子类构造方法中添加的部分组成。
写一个子类对象的构造方法:
- class Animal{
- public String name;
- public int age;
-
- public Animal(String name, int age) {
- this.name = name;
- this.age = age;
- }
- public void eat() {
- System.out.println(name+"正在吃饭!");
- }
- }
- class Dog extends Animal {
- public float weight;
-
- public Dog(String name,int age,float weight) {
- super(name, age);
- //调用父类的构造函数,来初始化此时子类继承过来父类的属性
- this.weight = weight;
- }
- public void bark() {
- System.out.println(name+"正在狗叫");
- }
-
- @Override
- public String toString() {
- return "Dog{" +
- "name='" + name + '\'' +
- ", age=" + age +
- ", weight=" + weight +
- '}';
- }
- }
- }
🟧子类对象构造时,需要先调用父类构造方法,将从父类继承下来的成员构造完整,
然后再调用子类自己的构造方法,将子类自己新增加的成员初始化完整。
⚜️提几点注意:
🤠(1)如果父类执行默认的构造方法,那么在子类构造方法的第一行默认含有super()的调用
🤠(2)如果父类构造方法是带有参数的,此时编译器给子类不会执行默认的构造方法,
这就要程序员自己给子类定义构造方法了
🤠(3)在子类构造方法中,super()调用父类构造时,必须是子类构造方法中第一条语句。
🤠(4)super()只能在子类构造方法中出现一次,并且不能和this同时出现
- class Animal{
- public String name;
- public int age;
-
- static {
- System.out.println("Animal的静态代码块!");
- }
-
- {
- System.out.println("Animal的实例代码块!");
-
- }
-
- public Animal() {
- System.out.println("Animal不带参数的构造方法!");
- }
-
- public Animal(String name, int age) {
- this.name = name;
- this.age = age;
- }
-
- public void eat() {
- System.out.println(name+"正在吃饭!");
- }
- }
- class Dog extends Animal {
- public float weight;
-
- static {
- System.out.println("Dog的静态代码块!");
- }
-
- {
- System.out.println("Dog的实例代码块!");
-
- }
- public Dog() {
- System.out.println("Dog的不带参数的构造方法!");
- }
- public Dog(String name, int age, float weight) {
- super(name, age);
- this.weight = weight;
- }
-
- public void bark() {
- System.out.println(name+"正在狗叫");
- }
-
- @Override
- public String toString() {
- return "Dog{" +
- "name='" + name + '\'' +
- ", age=" + age +
- ", weight=" + weight +
- '}';
- }
- }
- }
- public class Test01 {
- public static void main(String[] args) {
- Dog dog = new Dog();
- }
- }
大家可以看看执行后的结果:
是不是验证了 ——静态优先,由父及子
父类和子类对的静态方法——父类的实例和构造方法——子类的实例和构造方法
而且需要注意的是 静态代码块只执行一次。
| 范围 | private 私有 | default 默认 | protected 继承 | public 公开 |
|---|---|---|---|---|
| 同一包中的同一类 | ✓ | ✓ | ✓ | ✓ |
| 同一包中的不同类 | ✓ | ✓ | ✓ | |
| 不同包中的子类 | ✓ | ✓ | ||
| 不同包中的非子类 | ✓ |
我们可以清楚的看到,protected的访问范围。
继承类型可以分为以下几个:
(1)单继承

Java中只支持单继承。
(2)多级继承

一层一层的来继承。
(3)分层继承(不同类继承同一个类)

(1)final修饰成员变量时,变量就不能在修改并且属于常量。
(2)final修饰类时,此类不能被继承。
(3)final修饰方法是,此方法不能被重写。
继承 组合 继承指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,而且可以增加它自己的新功能的能力,直接点讲就是
🟪共性抽取,实现代码复用
🟦它的关系就是 is-a
🟩组合是通过对现有对象进行拼装即组合产生新的具有更复杂的功能。
🟦组合体现的是整体与部分,所拥有的关系,也就是has-a的关系
🟪也把这种方式的代码复用叫黑盒式代码复用
拓展:
😁复用性是面向对象的语言好处之一,
😁而这个复用性在java代码中,有三个表现形式:继承,组合,代理。
在两种都可行的情况下,优先使用组合,原因是组合比继承更加灵活,也更有助于代码维护。