Java——继承和多态

前言

上篇文章讲了类和对象,本篇就来讲述Java中的继承和多态,这两个也是非常重要的内容。

1. 继承

1.1 为什么需要继承

下面请看两段代码:

public class Cat {
    private int age;
    private String name;


    public Cat(String name) {
        this.name = name;
    }

    public void eat() {
        System.out.println("Cat eat");
    }


    public Cat(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public Cat() {
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

}

public class Dog {

    private int age;
    private String name;

    public Dog(String name) {
        this.name = name;
    }

    public void eat() {
        System.out.println("Dog eat");
    }

    public Dog(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public Dog() {
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

可以看到,这两个类的重复内容非常的多,如果能够提取共性,就可以解决这种问题,这时候就需要继承了。

1.2 继承的概念

继承是面向对象编程中的重要概念,它允许一个类(子类)基于另一个类(父类)来构建。在继承中,子类会继承父类的属性和方法,同时可以添加新的属性和方法,或者重写父类的方法。比如,狗和猫的的共性都是动物。狗类和猫类都可以继承动物类。

1.3 继承语法

修饰符 class 子类 extends 父类{
//...
}

将上面的例子进行修改:

public class Animal {
    private int age;
    private String name;

    public Animal(String name) {
        this.name = name;
    }

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

    public void sleep() {
        System.out.println(name+"睡觉");
    }
    public Animal(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public Animal() {
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

public class Cat extends Animal {
    public void mew(){
        System.out.println(getName()+"喵喵喵");
    }
}
public class Dog extends Animal {
    public void bark() {
        System.out.println(getName() +  "汪汪汪");
    }


}

public class Extend {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.setName("旺财"); //子类可以直接使用父类的方法
        dog.eat();
        dog.sleep();
        dog.bark();
        Cat cat = new Cat();
        cat.setName("加菲");
        cat.eat();
        cat.sleep();
        cat.mew();
    }
}

运行结果:
在这里插入图片描述
可以看到,代码量小了很多。
同时也可以看出来,子类可以访问父类的成员变量和成员方法。

1.4 super关键字

如果有子类的成员变量或者成员方法和父类的相同, 就需要super关键字。

1.4.1 super调用父类的构造方法

在子类的构造方法中使用 super() 来调用父类的构造方法。如果子类的构造方法没有显式调用父类的构造方法,Java会自动调用父类的无参构造方法。

class Animal {
    Animal() {
        System.out.println("父类构造器");
    }
}

class Dog extends Animal {
    Dog() {
        super(); // 调用父类的构造方法
        System.out.println("子类构造器");
    }
}

1.4.2调用父类的方法

在子类中使用 super.methodName() 来调用父类的方法。

class Animal {
    void eat() {
        System.out.println("动物在吃饭");
    }
}

class Dog extends Animal {
    void eat() {
        super.eat(); // 调用父类的eat方法
        System.out.println("狗在吃饭");
    }
}

1.4.3 访问父类的属性:

在子类中使用 super.variableName 来访问父类的属性。

class Animal {
    String name = "Animal";
}

class Dog extends Animal {
    String name = "Dog";

    void displayName() {
        System.out.println(super.name); // 访问父类的name属性
        System.out.println(name); // 访问子类的name属性
    }
}

1.5 final关键字

在Java中,final 是一个关键字,用于表示不可改变的。final 关键字可以用来修饰类、方法和变量。

注意:在方法中,final 关键字可以和 static 关键字一起使用,表示静态最终方法,不可被重写。
final 变量通常用大写字母命名,多个单词之间用下划线分隔,例如 MAX_VALUE

1.5.1 修饰类

当一个类被声明为 final 时,表示该类是最终类,不能被继承。

final class FinalClass {
    // 类的内容
}

1.5.2 修饰方法

当一个方法被声明为 final 时,表示该方法是最终方法,子类不能重写(在多态这一节会讲到)该方法。

class ParentClass {
    final void finalMethod() {
        // 方法的内容
    }
}

1.5.3 修饰变量

当一个变量被声明为 final 时,表示该变量是一个常量,只能被赋值一次。

final int constantValue = 10;

使用 final 关键字可以增加代码的安全性和可靠性,防止意外修改和继承。

2.多态

2.1 多态的概念

多态(Polymorphism)是面向对象编程中的重要概念,它允许不同类的对象对同一消息做出响应,即同一操作作用于不同的对象上会产生不同的行为

2.2 多态的条件

多态一般有如下条件:
继承:多态性基于类与子类之间的继承关系。子类继承父类的方法,可以重写(Override)父类的方法
重写(Override):子类重写父类的方法,方法名、参数列表和返回类型必须与父类中被重写的方法一致。重写的方法不能比父类方法的访问权限更严格。
父类引用指向子类对象:通过父类的引用来指向子类的对象,即向上转型。这样可以根据实际对象类型来调用方法。
运行时绑定:在运行时确定调用哪个方法,即动态绑定。当父类引用指向子类对象时,根据实际对象类型来调用方法。

多态体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法。

class Animal {
    public void sound() {
        System.out.println("动物的声音");
    }
}

class Dog extends Animal {
    @Override
    public void sound() {
        System.out.println("狗汪汪汪");
    }
}

class Cat extends Animal {
    @Override
    public void sound() {
        System.out.println("猫喵喵喵");
    }
}

public class AnimalExample {
    public static void main(String[] args) {
        Animal animal1 = new Dog(); // 父类引用指向子类对象
        Animal animal2 = new Cat(); // 另一个父类引用指向另一个子类对象

        animal1.sound(); // 调用子类 Dog 的 sound() 方法
        animal2.sound(); // 调用子类 Cat 的 sound() 方法
    }
}

在这个例子中,我们创建了一个 Animal 类作为父类,以及两个子类 Dog 和 Cat。在 main 方法中,我们使用父类 Animal 的引用分别指向 Dog 和 Cat 的对象,然后调用它们的 sound() 方法。这展示了多态性的特性,同一方法调用根据对象的实陋类型而有不同的行为。

2.3 重写

重写(Override)是面向对象编程中的一个重要概念,它允许子类重新定义(覆盖)父类中的方法。当子类重写父类的方法时,子类中的方法会覆盖父类中同名的方法,从而实现多态性。
重写的规则如下:
方法名、参数列表和返回类型必须与父类中被重写的方法完全相同。
子类重写的方法不能比父类方法的访问权限更严格。例如,如果父类中的方法是 public,那么子类中重写的方法不能是 private。
子类方法不能比父类方法抛出更宽泛的异常。如果父类方法抛出异常,子类方法可以不抛出异常,但不能抛出更宽泛的异常。
重写的主要目的是为了在子类中提供特定于子类的实现,从而允许不同类型的子类对象以不同的方式响应相同的方法调用。这样可以实现多态性,使得程序更加灵活和可扩展。

2.4 向上转型和向下转型

2.4.1 向上转型

向上转型(Upcasting)是面向对象编程中的一个重要概念,指的是将子类的实例赋值给父类类型的引用变量。这种转型是安全的,因为子类对象可以视作父类对象,而且可以访问父类中定义的方法和属性。
特点:
子类对象赋值给父类引用:通过向上转型,可以将子类实例赋值给父类类型的引用变量,如下所示:

ParentClass obj = new ChildClass();

下面有个例子:

class Animal {
    public void makeSound() {
        System.out.println("发出声音");
    }
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("汪汪汪");
    }

    public void wagTail() {
        System.out.println("摇尾巴");
    }
}

class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("喵喵喵");
    }

    public void purr() {
        System.out.println("咕噜咕噜");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myDog = new Dog();
        Animal myCat = new Cat();

        myDog.makeSound();  // 输出 "汪汪汪"
        myCat.makeSound();  // 输出 "喵喵喵"

        // 无法直接调用子类特有的方法,因为是用父类引用指向子类对象
        // myDog.wagTail();  // 编译错误
        // myCat.purr();     // 编译错误
    }
}

在这个例子中,我们创建了 Animal 类作为父类,以及 Dog 和 Cat 作为 Animal 类的子类。在主程序中,我们使用 Animal 类型的引用变量分别引用了 Dog 和 Cat 类型的对象。通过向上转型,我们可以调用 Animal 类中定义的 makeSound 方法,实现了多态性的效果。
需要注意的是,尽管我们用 Animal 类型的引用变量引用了 Dog 和 Cat 类型的对象,但我们无法直接调用子类特有的方法(如 wagTail 和 purr),因为这些方法是子类特有的,而 Animal 类型的引用变量无法直接访问子类特有的方法。

2.4.2 向下转型

向下转型(Downcasting)是将父类类型的引用变量转换为子类类型的引用变量的过程。这种转型需要在编译时确定类型,并且需要确保实际对象的类型是转换后的类型,否则会导致 ClassCastException 异常。

class Animal {
    public void makeSound() {
        System.out.println("发出声音");
    }
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("汪汪");
    }

    public void wagTail() {
        System.out.println("摇尾巴");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myDog = new Dog();

        // 向下转型并使用 instanceof 进行类型检查
        if (myDog instanceof Dog) {
            Dog myActualDog = (Dog) myDog;
            myActualDog.wagTail();  // 可以调用子类特有的方法
        } else {
            System.out.println("无法转型");
        }
    }
}

这段Java代码定义了一个Animal类和一个Dog类,其中Dog类是Animal类的子类。在Main类的main方法中,创建了一个Animal对象myDog,并用Dog类实例化它。然后通过向下转型和使用instanceof运算符进行类型检查,将myDog转型为Dog类的实例myActualDog,并调用了Dog类特有的方法wagTail()。
这段代码展示了面向对象编程中的继承和多态的概念。继承允许子类继承父类的属性和方法,而多态性允许同一个方法在不同子类中表现出不同的行为。在这里,Dog类重写了Animal类的makeSound()方法,并添加了自己的方法wagTail(),实现了多态性。

总结

以上就是继承和多态的内容了,希望大家看完之后能够对他们有更深入的了解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值