当前位置: 首页 > article >正文

六、面向对象编程(2)

继承是面向对象编程的三大特性之一(封装、继承、多态),它允许我们基于现有类创建新类,实现代码复用和层次化设计。本文将从六个核心方面系统解析Java继承机制。


一、继承快速入门

1.1 基本语法

class ParentClass {
    // 父类成员
}

class ChildClass extends ParentClass {
    // 子类特有成员
}

1.2 入门示例

class Animal {
    void eat() {
        System.out.println("Eating...");
    }
}

class Dog extends Animal {
    void bark() {
        System.out.println("Barking...");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog myDog = new Dog();
        myDog.eat();  // 继承自Animal
        myDog.bark(); // 自有方法
    }
}

二、继承的优势

  1. 代码复用:子类自动获得父类非私有成员
  2. 扩展性:在不修改父类的情况下扩展功能
  3. 多态基础:为方法重写和方法重载提供支持
  4. 层次结构:更符合现实世界的分类逻辑

三、权限修饰符详解

修饰符

类内部

同包

不同包子类

不同包非子类

private

默认(包)

protected

public

继承规则:

  • 子类继承父类的publicprotected成员
  • 默认访问权限成员只能在同包继承
  • private成员不可继承但可通过公有方法访问

典型继承场景:

class Parent {
    private String secret;      // 仅本类可见
    String familyName;          // 同包可见
    protected String heirloom;  // 子类可见
    public String motto;        // 全局可见
}

class Child extends Parent {
    void showInherited() {
        // System.out.println(secret);     // 编译错误
        System.out.println(familyName);   // 同包可访问
        System.out.println(heirloom);     // 子类可访问
        System.out.println(motto);        // 始终可访问
    }
}

四、方法重写(Override)

4.1 概念

当子类觉得父类方法不好用,或者无法满足父类需求时,子类可以重写一个方法名称、参数列表一样的方法,去覆盖父类的这个方法,这就是方法重写。

注意:重写后,方法的访问遵循就近原则

4.2 核心规则

1.重写的方法上面,可以加一个注解@Override,用于标注这个方法是复写的父类方法

2.子类复写父类方法时,访问权限必须大于或者等于父类方法的权限

public > protected > 缺省

3. 重写的方法返回值类型,必须与被重写的方法返回值类型一样,或者范围更小

4. 私有方法、静态方法不能被重写,如果重写会报错。

4.3 示例代码

  • 写一个A类作为父类,定义两个方法print1和print2
public class A {
    public void print1(){
        System.out.println("111");
    }

    public void print2(int a, int b){
        System.out.println("111111");
    }
}
  • 再写一个B类作为A类的子类,重写print1和print2方法。
public class B extends A{
    // 方法重写
    @Override // 安全,可读性好
    public void print1(){
        System.out.println("666");
    }


    // 方法重写
    @Override
    public void print2(int a, int b){
        System.out.println("666666");
    }
}

接下来,在测试类中创建B类对象,调用方法

public class Test {
    public static void main(String[] args) {
        // 目标:认识方法重写,掌握方法重写的常见应用场景。
        B b =  new B();
        b.print1();
        b.print2(2, 3);
    }
}

执行代码,我们发现真正执行的是B类中的print1和print2方法


五、子类成员访问特点

5.1 访问优先级

  1. 子类成员变量 > 父类成员变量
  2. 原则:在子类中访问其他成员(成员变量、成员方法),是依据就近原则的

定义一个父类,代码如下

public class F {
    String name = "父类名字";

    public void print1(){
        System.out.println("==父类的print1方法执行==");
    }
}

再定义一个子类,代码如下。有一个同名的name成员变量,有一个同名的print1成员方法;

public class Z extends F {
    String name = "子类名称";
    public void showName(){
        String name = "局部名称";
        System.out.println(name); // 局部名称
    }

    @Override
    public void print1(){
        System.out.println("==子类的print1方法执行了=");
    }

    public void showMethod(){
        print1(); // 子类的
    }
}

接下来写一个测试类,观察运行结果,我们发现都是调用的子类变量、子类方法。

public class Test {
    public static void main(String[] args) {
        // 目标:掌握子类中访问其他成员的特点:就近原则。
        Z z = new Z();
        z.showName();
        z.showMethod();
    }
}
  • 如果子类和父类出现同名变量或者方法,优先使用子类的;此时如果一定要在子类中使用父类的成员,可以加this或者super进行区分。
public class Z extends F {
    String name = "子类名称";

    public void showName(){
        String name = "局部名称";
        System.out.println(name); // 局部名称
        System.out.println(this.name); // 子类成员变量
        System.out.println(super.name); // 父类的成员变量
    }

    @Override
    public void print1(){
        System.out.println("==子类的print1方法执行了=");
    }

    public void showMethod(){
        print1(); // 子类的
        super.print1(); // 父类的
    }
}

六、构造器访问特点

6.1 构造器调用规则

  1. 子类构造器必须调用父类构造器
  2. 默认调用父类无参构造器super()
  3. 显式调用必须放在构造器首行

6.2 示例分析

class Person {
    private String name;
    
    public Person(String name) {
        this.name  = name;
        System.out.println("Person 构造器执行");
    }
}

class Student extends Person {
    private int grade;
    
    public Student(String name, int grade) {
        super(name);  // 必须首行调用
        this.grade  = grade;
        System.out.println("Student 构造器执行");
    }
}

// 测试输出:
Student s = new Student("Alice", 10);
// 输出顺序:
// Person构造器执行
// Student构造器执行

最佳实践与注意事项

  1. 遵循is-a关系进行继承设计
  2. 谨慎使用继承层级(建议不超过3层)
  3. 优先使用组合替代深层继承
  4. 注意构造器调用链的执行顺序
  5. 使用@Override注解增强代码可读性


http://www.kler.cn/a/547281.html

相关文章:

  • STM32之SG90舵机控制
  • 【快速入门】Unity 常用组件(功能块)
  • 在illustrator中,如何绘制一个简单的茶壶?
  • Kubernetes控制平面组件:etcd(二)
  • Python学习心得编码与解码
  • 一维差分算法篇:高效处理区间加减
  • Mac安装JD-GUI
  • Postman入门:环境变量和全局变量
  • 【Go并发编程】Goroutine 调度器揭秘:从 GMP 模型到 Work Stealing 算法
  • 「软件设计模式」工厂方法模式(Factory Method) vs 抽象工厂模式(Abstract Factory)
  • arm linux下的中断处理过程。
  • 如何使用Jsoup获取动态加载的内容
  • Banana Pi OpenWRT One 官方路由器的第一印象
  • matlab平面波展开法计算的二维声子晶体带隙
  • 【R语言】非参数检验
  • Vue响应式原理实现总结(数据劫持Object.defineProperty/Proxy+发布订阅者设计模式)
  • 【C++】32.C++11​(4)
  • 第二月:学习 NumPy、Pandas 和 Matplotlib 是数据分析和科学计算的基础
  • 图论- Dijkstra算法
  • 【Linux】进程间通信——管道通信