java面向对象(2)(继承)
文章内容发布于 5 天前;最后修改于 3 日前。其中的信息可能发生变化或产生更改,敬请留意。

什么是继承

java中提供extends关键字,使得两个类建立起继承和被继承的关系,其语法是:public class <子类> extends <父类>.

其中,继承的类称为子类(派生类)、被继承的类称为父类(基类、超类)

我们可以举例如下

有猫类和狗类,它们都继承自动物类。动物有自己的nickname,会睡觉、吃饭。而猫类和狗类都继承自动物类,且在动物类之上,猫类会舔毛,而狗类会摇尾巴。

使用继承的好处

  • 可以把多个子类中重复的代码合并到父类,提高代码的复用性。
  • 子类可以在父类的基础上按需添加更多的功能

什么时候适合用继承

  • 当类与类之间存在相同(共性)的内容,并且满足子类是父类中的一种,就可以考虑使用继承来优化代码。

继承的特点

java中,只支持单继承、不支持多继承,但支持多层继承。

  • 只支持单继承、不支持多继承:一个子类只能继承一个父类;(这点和CPP中完全不同)。
  • 支持多层继承:A类可以继承父类B,而B类可以同时作为子类继承父类C。对于A来说,C是A的间接父类,B是A的直接父类。
  • 每一个类都直接或间接继承自Object类,Object类是JVM自行生成的。

子类可以继承父类什么内容

**非私有**(\public\、\protected\ **私有**(\private\
构造方法 ❌子类不能继承 ❌子类不能继承
成员变量 ✅子类可以继承 ✅子类可以继承(但不可直接访问)
成员方法 ✅子类可以继承 ❌子类不能继承

说明:

  1. 成员变量在继承时,子类对象会包含完整的父类成员变量和子类自身定义的成员变量,每个对象实例在堆中拥有各自独立的内存空间。
  2. 如果子类没有重写继承的方法,子类和父类的方法在执行时指向方法区中的同一段方法代码;如果重写了,则各自在方法区中有自己的方法代码。
  3. 父类私有成员变量,子类可以继承但不可以直接访问:子类对象在内存中确实包含了父类的私有成员变量,但是在子类的代码中,不能直接用变量名来访问父类的私有成员。
  4. 只有父类中的虚方法(非private修饰、非ststic修饰、非final修饰)、且方法非私有才可以被子类继承;准确来说,成员方法的继承,只有虚方法才可以被继承

各种父类元素的继承情况

构造方法的继承情况

public class InheritanceDEMO {
    public static void main(String[] args) {
        Subclass s1 = new Subclass(); // ✅ 可以正常编译,因为 Subclass 存在对应的构造方法
        // Subclass s2 = new Subclass("bingCat"); // ❌ 不可以正常编译,因为子类不会继承父类的构造方法
    }
}
class Superclass {
    String catName;
    public Superclass() {}
    public Superclass(String catName) {
        this.catName = catName;
    }
}
class Subclass extends Superclass {
    public Subclass() {}
}

由于构造方法的方法名是和类名相同的,子、父类的类名不同,自然无法使用父类的构造方法,所以也不会继承其构造方法。

在如上的代码中,Subclass s1 = new Subclass();可以正常编译,因为 Subclass 存在对应的构造方法;Subclass s2 = new Subclass("bingCat");不可以正常编译,因为子类不会继承父类的构造方法.

如果强行编译如上代码中的Subclass s2 = new Subclass("bingCat");,则会报错如下:会认为没有对应的构造方法。

成员变量的继承情况

成员变量在继承的时候:非私有(publicprotected)成员变量是可以继承且可以直接访问的;私有(private)成员变量是可以继承但是不能直接访问的。

public class InheritanceDEMO {
    public static void main(String[] args) {
        Subclass s = new Subclass();
    }
}
class Superclass {
    public String catName;
    private int catAge;
}
class Subclass extends Superclass {
    public String catFood;
    public void showCat() {
        System.out.println(catName); // ✅ 可以正常编译,因为 Subclass 会继承 Superclass 的成员变量,且非 private 修饰的成员变量可以直接访问
        // System.out.println(catAge); // ❌ 不可以正常编译,因为被 private 关键字修饰的成员变量可以继承但是无法直接访问
    }
}

如上的代码中,子类中的System.out.println(catName);语句可以正常编译,因为 Subclass 会继承 Superclass 的成员变量,且非 private 修饰的成员变量可以直接访问;System.out.println(catAge);语句不可以正常编译,因为被 private 关键字修饰的成员变量可以继承但是无法直接访问。

如果强行编译如上代码中的System.out.println(catAge);语句,则会报错如下:会清晰准确地告知具体的成员变量是private关键字修饰的。

如果父类中的成员变量是private修饰的,同样会被继承,但是无法直接访问。如果需要访问,可以在父类中定义对应的Getter或者Setter方法来使得子类可以访问、修改父类中private关键字修饰的成员变量。

成员方法的继承情况

虚方法:非private修饰、非ststic修饰、非final修饰。

父类会将自己的虚方法存储在虚方法表中,父类在被继承的时候,会将虚方法表被子类继承,继承时,子类会将自己本身的虚方法添加到继承的虚方法表中。这样有助于提升性能。

只有父类中的虚方法、且方法非私有才可以被子类继承。

public class InheritanceDEMO {
    public static void main(String[] args) {
        Subclass s = new Subclass();
        s.superPublic(); // ✅ 正常编译,因为对应方法可以被调用,父类中的 superPublic 方法是 public 修饰的,可以被子类继承。
        // s.superPrivate(); // ❌ 编译错误,因为对应方法是父类中的superPrivate,被private关键字修饰,子类无法继承
    }
}
class Superclass {
    public void superPublic() {}
    private void superPrivate() {}
}
class Subclass extends Superclass {}

如上代码中,s.superPublic();语句可以正常编译,因为对应方法可以被调用,父类中的 superPublic 方法是 public 修饰的,可以被子类继承;s.superPrivate();语句无法被编译,因为对应方法是父类中的superPrivate,被private关键字修饰,子类无法继承。

如果强行编译s.superPrivate();语句,则报错如下:因为子类未继承superPrivate方法,自然找不到对应的方法。

在如上代码中,父类中的superPublic()可以被添加到虚方法表中。

各种继承元素的访问特点

成员变量的访问特点

遵循就近原则:先在局部位置中寻找,再在所属的类中寻找,再到父类中寻找。

public class InheritanceDEMO {
    public static void main(String[] args) {
        Subclass s = new Subclass();
        System.out.println(s.cat);
    }
}
class Superclass {
    public String cat = "Sakura";
}
class Subclass extends Superclass {
    public String cat = "leffay";
}

成员方法的访问特点

  • 直接调用仍然满足就近原则;
  • 也可以使用super直接访问直接父类的成员方法。

如果子类重写父类的方法,也就是方法重写,但是在继承中子类和父类出现相同的方法名、相同的形式参数列表、返回类型相同子类小于等于父类、访问权限不能更加严格(可以相同的访问权限或者更加宽松),则子类的方法就是方法的重写。

需要说明的是,方法的重写需要满足如下的注意事项:

  1. 重写的方法名必须和被重写的方法名相同;
  2. 重写方法的形参列表必须和被重写方法的形参列表(包括顺序)相同;
  3. 重写方法的返回值类型,必须小于等于被重写方法的返回值类型;
  4. 重写方法的访问权限必须大于等于被重写方法的访问权限。
  5. 被重写方法被privateststicfinal修饰时,不能重写。

方法是否能重写的本质,是被添加到虚方法表中的方法才能被重写。

方法的重写涉及到多态,会在后续学习多态的时候继续了解。

重写方法的时候使用**@Override**重写注解

  1. @Override是放在重写的方法上,校验子类重写时语法是否正确。
  2. 加上注解后如果有红色波浪线(idea中是在@Override文字底下存在红色波浪线),则表示语法错误
  3. 重写方法时@Override不是强制的,但是非常推荐都加上。

当子类重写父类方法时,子类的虚方法表中对应位置的方法引用会指向子类自己的实现,而不是父类的实现。未重写的方法则继续指向父类的方法实现。

构造方法的访问特点

父类中的构造方法不会被子类继承,不论是非私有还是私有构造方法。

子类中的所有构造方法,都会先默认指向父类中的无参构造方法,再执行自己的构造方法。

public class InheritanceDEMO {
    public static void main(String[] args) {
        Subclass s1 = new Subclass();
        Subclass s2 = new Subclass(1);
    }
}
class Superclass {
    public Superclass() {
        System.out.println("Superclass Default Constructor");
    }
}
class Subclass extends Superclass {
    public Subclass(int a) {
        System.out.println("Subclass Parameterized Constructor");
    }
    public Subclass() {
        System.out.println("Subclass Default Constructor");
    }
}

总结如下

  • 子类不能继承父类的构造方法,但是可以直接使用super()调用对应的父类构造方法。
  • 子类的构造方法中,默认会调用super(),即父类的无参构造方法
  • 如果需要使用父类的有参构造,需要自行手动编写代码。

this和super关键字

  • this指向当前对象,用于指向当前方法调用者的地址值。
  • super指向父类对象,代表父类存储空间。

访问成员变量

public class InheritanceDEMO {
    public static void main(String[] args) {
        Subclass s = new Subclass();
        s.showcat();
    }
}
class Superclass {
    public String cat = "bingCat";
}
class Subclass extends Superclass {
    public String cat = "linCat";
    public void showcat() {
        String cat = "Sakuralaffey";
        System.out.println(cat);
        System.out.println(this.cat);
        System.out.println(super.cat);
    }
}

在子类中,只可以编写一个super,只能访问直接父类成员变量,不可以访问间接父类成员变量。

访问位置 语法 优先级 说明
局部变量 <变量名> 1 当前方法/代码块内
当前类成员 this.<变量名> 2 当前类的成员变量
直接父类成员 super.<变量名> 3 直接父类的可访问成员
间接父类成员 需转型或特定方法 4 需要通过其他方式访问

访问成员方法

不能通过对象引用使用thissuperthis**super只能在类的非静态方法内部使用**

public class InheritanceDEMO {
    public static void main(String[] args) {
        Subclass s = new Subclass();
        // s.this.showMyCat();
        // s.super.showMyCat();
    }
}
class Superclass {
    public void showMyCat() {
        System.out.println("SakuraLaffey");
    }
}
class Subclass extends Superclass {
    @Override
    public void showMyCat() {
        System.out.println("bingCat");
    }
}

如上代码中,s.this.showMyCat(); 语句和 s.super.showMyCat();语句是通过对象引用使用thissuper,这样会导致编译出错,因为thissuper只能在类的非静态方法内部使用。如果强制编译则会报错。

如果修改,则应该是如下代码

public class InheritanceDEMO {
    public static void main(String[] args) {
        Subclass s = new Subclass();
        s.cats();
    }
}
class Superclass {
    public void showMyCat() {
        System.out.println("SakuraLaffey");
    }
}
class Subclass extends Superclass {
    @Override
    public void showMyCat() {
        System.out.println("bingCat");
    }
    public void cats() {
        this.showMyCat();
        super.showMyCat();
    }
}

访问构造方法

使用this()可以直接访问本类中其他构造方法。如果类存在继承关系,则如果使用this(),JVM就不会再默认去调用super()来构造对象。

且,无论使用this(),还是super(),都必须写在构造函数的第一行

构造方法的调用顺序

public class OOPAbstract {
    public static void main(String[] args) {
        Cat cat = new Cat();
    }
}
class Animal{
    public Animal(){
        System.out.println("Animal 类构造方法");
    }
}
class Cat extends Animal{
    public Cat(){
        System.out.println("Cat 类构造方法");
    }
}

如果两个类存在继承和被继承关系的时候,子类初始化的时候会默认调用父类的无参构造方法(编译器自动添加),如果父类没有,则子类的构造方法需要手动使用super(<基类构造方法的形参>)来初始化。如果子类实例化的时候没有调用父类的任意一个构造方法,则编译报错。

关忆点

  1. 调用顺序:父类构造 → 子类构造
  2. super() 的位置:必须是子类构造方法的第一条语句
  3. 隐式规则
    • 如果父类有无参构造,子类可不写super()(编译器自动添加)
    • 如果父类只有有参构造,子类必须显式调用super(参数)

this和super的总结

关键字 访问成员变量 访问成员方法 访问构造方法
this 使用this.<成员变量>,访问本类成员变量 使用this.<成员方法>(),访问本类成员方法 使用this(),访问本类构造方法
super 使用super.<成员变量>,访问父类成员变量 使用super.<成员方法>(),访问父类成员方法 使用super(),访问父类构造方法
文章「java面向对象(2)(继承)」,由本站用户「Admin」发布。文章仅代表Admin观点,不代表本站立场。
页面网页地址「https://xiaozhiyuqwq.top/p/2857」。
如您对文章及其附件提出版权主张,或进行引用转载等,请查看我们的【版权声明】
本页面暂时没有评论......

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇