Java继承

继承是Java面向对象编程的三大特性之一,方便实现代码的高效复用和层次化组织,是里氏替换原则的一种体现。

继承的基本概念
通过extends关键字,子类可以继承父类的属性和方法,形成类之间的“is-a”关系。这种机制不仅减少了代码冗余,更建立了清晰的类层次结构。

继承的优势
代码复用:避免重复编写相同功能的代码
扩展性:子类可在继承基础上添加新功能
多态基础:为方法重写和运行时多态提供支持

/**
 * 父类
 */
public class Animal {
    // 属性
    protected String name;
    //默认的权限修饰符,age,同一个package可继承
    String age;

    public Animal() {
        System.out.println("Animal无参构造器");
    }

    // 构造方法
    public Animal(String name) {
        this.name = name;
        System.out.println("Animal有参构造器");
    }

    // 通用方法
    public void eat() {
        System.out.println(name + "正在吃东西");
    }

    //将被重写的方法
    public void makeSound() {
        System.out.println("动物发出声音");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}
/**
 * 子类dog
 */
public class Dog extends Animal {
    public Dog() {
        //如果父类Animal有无参构造函数,子类构造函数不需要显式调用父类构造方法,编译器会默认调用父类的无参构造方法(子类总需要调用父类的构造方法)
    }

    public Dog(String name) {
        //子类构造器必须调用父类构造器
        //如果父类Animal没有无参构造函数,子类构造函数必须显式调用父类构造方法
        //如果父类Animal有无参构造函数,子类构造函数不需要显式调用父类构造方法,编译器会默认调用父类的无参构造方法(即子类构造器必须调用父类构造器)
        super(name);
    }

    /**
     * 方法重写
     */
    // Dog特有的方法
    public void fetch() {
        System.out.println(name + "正在捡球");
    }

    @Override
    public void makeSound() {
        System.out.println(name + "汪汪叫!");
    }
}
/**
 * 子类bird
 */
public class Bird extends Animal {
    // Bird特有的属性
    private boolean canFly;

    public Bird(String name, boolean canFly) {
        super(name);
        this.canFly = canFly;
    }

    // Bird特有的方法
    public void fly() {
        if (canFly) {
            System.out.println(name + "正在飞翔");
        }
    }

    /**
     * 方法重写
     */
    @Override
    public void makeSound() {
        System.out.println(name + "咕咕叫!");
    }

    public boolean isCanFly() {
        return canFly;
    }

    public void setCanFly(boolean canFly) {
        this.canFly = canFly;
    }
}

运行测试:

public class AnimalTest {
    public static void main(String[] args) {
        // 多态:父类引用指向子类对象
        Animal noSuperDog = new Dog();
        Animal myDog = new Dog("旺财");
        Animal myBird = new Bird("小翠", true);
        Animal myPenguin = new Bird("企鹅先生", false);

        // 多态调用 - 运行时确定具体方法
        System.out.println("=== 多态演示 ===");
        myDog.makeSound();     // 输出:旺财汪汪叫!
        myBird.makeSound();    // 输出:小翠叽叽咕咕叫
        myPenguin.makeSound(); // 输出:企鹅先生咕咕叫
    }
}

运行结果:
Animal无参构造器
Animal有参构造器
Animal有参构造器
Animal有参构造器
=== 多态演示 ===
旺财汪汪叫!
小翠咕咕叫!
企鹅先生咕咕叫!

总结:
1.父类不同权限修饰符的影响

    public String publicName;      // 任何地方都可访问
    protected String protectedName; // 同包或子类可访问
    String defaultName;           // 同包可访问
    private String privateName;   // 仅本类可访问

简单讲就是说,子类会继承除private修饰之外的属性值。

2.super关键字的使用
super关键字的使用与 Java 的构造器机制有关。
子类构造方法必须调用父类构造方法,如果不调用 super(name),编译会报错。

调用规则:
子类构造器第一行必须是 super(...)。
如果父类没有无参构造器,子类必须显式调用 super(...)。
如果父类有无参构造器,如果子类没有显式调用 super(...),编译器会自动调用父类的无参构造器。

3.必须调用super(...)的原因

父类和子类的继承关系是"is-a",子类需要继承使用父类中属性,必须保证父类是一个正确初始化的父类对象,
所以必须先初始化父类部分,再初始化子类部分,保证对象的完整性,避免部分初始化的对象。
posted @ 2025-10-30 16:07  佩特莉可  阅读(3)  评论(0)    收藏  举报