前言:

        在面向对象编程中,继承是实现代码复用,建立类之间层次关系的重要机制。通过继承,我们可以将多个类的公共部分抽取到父类中,子类只需要关注自己特有的属性和行为,从而让代码更加简洁,易于维护。

        本文将从为什么需要继承讲起,详细解析java中继承的语法,成员访问规则,super关键字,构造方法互动,protected访问权限,代码块初始化顺序,final的限制作用。

目录

前言:

一.为什么需要继承——代码的复用

二.继承的基本语法

2.1什么是继承?

2.2  extends关键字

三.父类成员访问规则

3.1成员变量访问:就近原则

3.2成员方法访问

四.super关键字:显示访问父类成员

五.子类构造方法与super()调用链

六.super和this的对比

七.继承关系下的初始化顺序(时间轴)

八.protected访问权限

九.final关键字:继承的“终结者”

总结:


一.为什么需要继承——代码的复用

设想我们有两个类:Dog和Cat,它们都有姓名,年龄,体重,都会吃饭睡觉。如果不使用继承,我们需要在两个类中重复编写同样的字段和方法:

//Dog.java
public class Dog{
    String name;
    int age ;
    float weight;

    public void eat(){
        System.out.println(name+"正在吃饭");
    }

    public void sleep(){
        System.out.println(name+"正在睡觉");
    
    }
    void bark() {
        System.out.println(name + "汪汪汪~~~");
    }

}

//Cat.java
public class Cat {
    String name;
    int age;
    float weight;

    public void eat() {
        System.out.println(name + "正在吃饭");
    }
    public void sleep() {
        System.out.println(name + "正在睡觉");
    }
    void mew() {
        System.out.println(name + "喵喵喵~~~");
    }
}

大量的代码重复,这不仅导致代码臃肿,也增加了维护成本——如果要修改动物的通用行为,必须要去修改每个类。

面向对象编程为我们提供了解决方案:继承。继承允许我们抽取共性,形成层次结构,让子类自动拥有父类的特性,从而实现“站在巨人的肩膀上”编程。

二.继承的基本语法

2.1什么是继承?

        继承是面向对象程序设计中实现代码复用的重要手段。它允许程序员在保持原有类特性的基础上进行拓展,增加新功能。

        父类:被继承的类,代表共性。

        子类:继承父类的类,代表个性。

2.2  extends关键字

        在Java中,使用extends关键字来表示继承关系。

语法:

        修饰符    class  子类   extends   父类{    //子类内容    }

示例:

// Animal.java (父类)
public class Animal {
    String name;
    int age;

    public void eat() {
        System.out.println(name + "正在吃饭");
    }
    public void sleep() {
        System.out.println(name + "正在睡觉");
    }
}

// Dog.java (子类)
public class Dog extends Animal {
    void bark() {
        System.out.println(name + "汪汪汪~~~");
    }
}

// Cat.java (子类)
public class Cat extends Animal {
    void mew() {
        System.out.println(name + "喵喵喵~~~");
    }
}

// 测试
public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name = "旺财";
        dog.eat();   // 继承自Animal
        dog.bark();  // 自己的方法
    }
}

        我们通常会将字段设为private,并通过protected的getter/setter方法来访问,以符合严格的封装原则。

注意:子类应添加自己特有的成员,否则单纯继承无意义。

三.父类成员访问规则

3.1成员变量访问:就近原则

        无同名变量:子类直接访问继承来的变量。

        有同名变量:遵循就近原则,优先访问子类的自己的变量。

public class Base{
    int a=10;
    int b=20;
}

public class Derived extends Base{
    int a=100;        //同名变量
    public void method(){
        System.out.println(a);    //输出子类的a  100
        System.out.println(b);    //输出父类的b  20
    }
}

若想强制访问父类的同名成员,需要使用super关键字。

3.2成员方法访问

        方法名不同:先找子类,再找父类,找不到编译报错。

        方法名:相同(重写/重载):

        若参数列表不同(重载),根据调用参数决定。

        若参数列表完全相同(重写),则有限调用子类的方法(多态特性)。

重写(Override)要求方法名,返回类型,参数列表完全一致,子类访问权限不能严于父类。

四.super关键字:显示访问父类成员

        当子类和父类出现相同名字的成员时,super可以帮我们访问父类的成员。

public class Derived extends Base {
    int a = 100;

    public void method() {
        System.out.println(a);      // 子类自己的 a
        System.out.println(super.a);// 父类的 a
        super.methodA();            // 调用父类方法
    }
}

        super的三大用法

1.访问父类的成员变量:super.父类变量名

2.访问父类的成员方法:super.父类方法名()

3.调用父类的构造方法:super(参数列表)

五.子类构造方法与super()调用链

核心原则:先有父,再有子

        子类对象包含两部分:从父类继承下俩的成员+自己新增的成员。因此,构造子类对象之前必须先构造父类对象。

规则详解:

        默认调用:如果子类构造方法中没有显式写super(),编译器会自动插入super,即调用父类的无参构造方法。

        显式调用:如果父类没有无参构造(例如定义了带参构造),子类必须再第一行显式调用super(参数)。

        唯一性和顺序:super()必须是子类构造方法中的第一条语句,且只能出现一次。

public class Base{
    public Base(int a ){
        System.out.println("Base构造"+a);
    
    }

}

public class Derived extends Base{
    public Derived(){
        super(10);    //必须显式调用,且位于第一行
        System.out.println("Derived 构造")
    }
}

super()只能在子类构造方法中使用,且必须是第一条语句。

super()和this()不能同时出现(因为都要在第一行)。

若父类没有无参构造,子类未显式调用父类其他构造方法,编译报错。

六.super和this的对比

this super
本质 当前对象的引用 子类对象中父类部分的引用
访问范围 本类的成员 父类的成员
构造方法的调用

this(...)调用本类其他

构造方法

super(...)调用父类构造方法
是否必须第一行 是,与super()排斥 是,与this排斥
是否默认存在 除非手动调用this

子类构造方法中默认有super()

父类有无参构造时

七.继承关系下的初始化顺序(时间轴)

“静态优先,父先子后”        父静-->子静-->父实-->父构-->子实-->子构

静态代码块:只执行一次,在类加载的时执行。父类优先于子类。

实例代码块:每次创建对象时。父类的实例块在父类构造方法之前执行

构造方法:最后执行。

class Person {
    public Person(String name, int age) {
        System.out.println("Person构造");
    }
    { System.out.println("Person实例代码块"); }
    static { System.out.println("Person静态代码块"); }
}

class Student extends Person {
    public Student(String name, int age) {
        super(name, age);
        System.out.println("Student构造");
    }
    { System.out.println("Student实例代码块"); }
    static { System.out.println("Student静态代码块"); }
}

public class Test {
    public static void main(String[] args) {
        new Student("张三", 19);
        System.out.println("============");
        new Student("李四", 20);
    }
}

八.protected访问权限

        protected允许:

同一个包中的任何类访问。

不同包中的子类访问从父类继承下来的protected成员。

注意:在不同包的子类中,不能通过其他子类对象访问其protected成员

// 包 demo1
public class Base {
    protected int b = 100;
}

// 包 demo2
import demo1.Base;
public class Derived extends Base {
    void test() {
        System.out.println(b);        // OK,继承下来的 protected
        Base obj = new Base();
        // System.out.println(obj.b); // 错误!不同包中不能通过父类对象访问 protected
    }
}

九.final关键字:继承的“终结者”

        为了防止类被继承或方法被重写,java提供了final。

修饰类:该类不能被继承(如String类)

修饰方法:该方法不能被重写。

修饰变量:变量为常量,不能被修改。

final class Animal { }   // 不可被继承
// class Dog extends Animal { } // 编译错误

class Parent {
    final void method() { }
}
class Child extends Parent {
    // void method() { } // 编译错误,不能重写 final 方法
}

总结:

        语法基础:extends和super的使用

        底层逻辑:构造方法的调用链和初始化顺序

        访问控制:protected允许不同包子类访问,但不能通过其他子类对象访问。

        限制手段:final可以限制继承,重写,修改

更多推荐