【一步一步了解Java系列】:重磅多态

简介: 【一步一步了解Java系列】:重磅多态

看到这句话的时候证明:此刻你我都在努力

加油陌生人 2.png

何为多态

在Java中,多态(Polymorphism)是一种允许不同类的对象对同一消息做出响应的能力,即同一个接口可以被不同的实例以不同的方式实现。多态性是面向对象编程的一个核心概念,它使得代码更加灵活和可扩展。

多态性主要通过以下几种方式实现:


方法重载(Overloading):这是编译时多态的一个例子。方法重载允许同一个类中有多个同名方法,只要它们的参数列表不同(参数的类型、数量或顺序不同)。

方法重写(Overriding):这是运行时多态的一个例子。当子类继承父类时,子类可以重写父类的方法。如果子类对象调用了一个被重写的方法,将执行子类中的方法实现,而不是父类中的实现。

接口实现:一个类可以实现一个或多个接口,接口定义了一组方法规范,具体的实现类必须提供这些方法的具体实现。不同的实现类可以以不同的方式实现同一个接口中定义的方法。

抽象类:抽象类可以包含抽象方法,这些方法没有具体的实现,必须由继承抽象类的子类来实现。这也是一种多态的体现,因为不同的子类可以提供不同的实现。

多态的使用可以带来以下好处:


代码复用:通过继承和接口实现,可以减少代码的重复编写。

扩展性:通过多态,可以在不修改现有代码的情况下,引入新的类和对象。

灵活性:多态允许程序在运行时动态地绑定方法调用,使得程序更加灵活。

多态是Java中实现开闭原则(对扩展开放,对修改封闭)的关键机制之一,它允许程序更容易适应变化,同时保持代码的稳定性和可维护性。

多态实现的条件:


必须在继承体系下

子类必须要对父类中方法进行重写

通过父类的引用调用重写的方法

总的来说:多态即是不同对象,不同的的态度。

方法重载的多态

方法重载在前面其实已经说过了,下面是一个方法重载多态的情况:

public class Cat {

    String type="猫咪";
    public void eat(){
        System.out.println(type+"吃猫粮");

    }


    public void eat(int n){

        System.out.println(type+"吃"+n+"两猫粮");

    }

}

class Test{
    public static void main(String[] args) {
        Cat cat=new Cat();
        cat.eat();
        cat.eat(1);

    }


}


上面我们对方法进行重载,然后传参不同时,同一个方法却呈现不同的打印方式即(不同的形态)。

方法重写的多态

我们先要认识,何为重写:

在Java中,重写(Overriding)是指子类提供一个特定的实现,覆盖从父类继承来的方法的实现。这是运行时多态的一个体现,意味着在程序运行时,会根据对象的实际类型来调用相应的方法。

要实现方法重写,需要满足以下条件:


方法名、参数列表和返回类型:子类重写的方法必须具有与父类被重写方法相同的方法名、参数列表和返回类型。如果返回类型不同,则不是重写,而是重载(Overloading)。

访问权限:子类重写的方法不能具有比父类更严格的访问权限。例如,如果父类中的方法是public的,子类重写的方法也必须是public或protected,但不能是private。

非静态方法:重写必须发生在非静态方法上。静态方法(Static methods)不能被重写。

非最终方法:如果父类中的方法是final的,则不能被重写。

下面是一个简单的示例,展示如何在Java中重写方法:

class Animal {
    public void sound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    @Override // 这是一个注解,用于指示该方法重写了父类的方法
    public void sound() {
        System.out.println("Dog barks");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myAnimal = new Dog(); // 向上转型
        myAnimal.sound(); // 输出 "Dog barks",展示了运行时多态
    }
}


在这个例子中,Dog 类继承自 Animal 类,并重写了 sound() 方法。当我们创建 Dog 类的实例并将其向上转型为 Animal 类型时,调用 sound() 方法会执行 Dog 类中重写的方法,而不是 Animal 类中的原始方法。这就是多态性的一个典型应用,它允许程序在运行时根据对象的实际类型来确定调用哪个方法。

了解完重写我们在看看,下面的代码:

public class Animal {
    String name="aaaa";

    public void eat(){
        System.out.println("吃东西。。。。。");

    }
}


class Dog extends Animal{

    String name;

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

    public void eat(){
       System.out.println("吃狗粮。。。");


    }




}

class Cat extends Animal{

    String name;

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

    public void eat(){
        System.out.println("吃猫粮。。。");


    }




}

class Test{

    public static void main(String[] args) {
        Animal animal=new Dog("旺财");
       animal.eat();
        animal=new Cat("小黑");
        animal.eat();
     
    }



}


我们在调用eat()方法时却呈现了不同的形态,即:一个吃猫粮,一个吃狗粮。

我们也可以用静态方法实现多态如下:

public class Animal {
    String name="aaaa";

    public void eat(){
        System.out.println("吃东西。。。。。");

    }
}


class Dog extends Animal{

    String name;

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

    public void eat(){
        System.out.println("吃狗粮。。。");


    }




}

class Cat extends Animal{

    String name;

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

    public void eat(){
        System.out.println("吃猫粮。。。");


    }




}

class Test{
public static void eat(Animal animal){
    animal.eat();

}
    public static void main(String[] args) {
        Dog dog=new Dog("旺财");
       eat(dog);
       Cat cat=new Cat("小黑");
       eat(cat);

    }



}


这里我们在Test中实现了一个静态方法eat(Animal animal)然后传递一个对象进去即可完成多态。

其实上面的代码还涉及了,类的向上转型。我们接下来就讲讲向上转型和向下转型。

向上转型和向下转型

在Java中,向上转型(Upcasting)和向下转型(Downcasting)是面向对象编程中多态性的一部分,它们允许我们处理不同类型的对象,但以更通用的类型进行操作。

向上转型(Upcasting)

向上转型是指将子类对象赋值给父类引用的过程。向上转型是安全的,因为子类是父类的特化。这意味着子类继承了父类的所有属性和方法,所以子类对象可以被看作是父类对象。


示例代码:

class Animal {
    void makeSound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    void makeSound() {
        System.out.println("Dog barks");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myAnimal = new Dog(); // 向上转型
        myAnimal.makeSound(); // 将调用Dog类的makeSound方法
    }
}


在这个例子中,Dog 类是 Animal 类的子类。我们创建了一个 Dog 类的实例,并将这个实例赋值给 Animal 类型的引用 myAnimal。由于向上转型是安全的,编译器允许这样做,并且当我们调用 makeSound() 方法时,将调用 Dog 类中重写的方法。

向下转型(Downcasting)

向下转型是指将父类对象赋值给子类引用的过程。向下转型是不安全的,因为父类引用可能没有指向实际的子类对象。如果向下转型不正确,将会导致 ClassCastException。

示例代码:

class Animal {
    void makeSound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    void makeSound() {
        System.out.println("Dog barks");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myAnimal = new Dog();
        Dog myDog = (Dog) myAnimal; // 向下转型

        if (myAnimal instanceof Dog) {
            Dog myDogSafe = (Dog) myAnimal; // 安全的向下转型
            myDogSafe.makeSound(); // 将调用Dog类的makeSound方法
        } else {
            System.out.println("myAnimal is not a Dog");
        }
    }
}


在这个例子中,我们首先向上转型,将 Dog 对象赋值给 Animal 类型的引用 myAnimal。然后我们尝试向下转型,将 myAnimal 转换为 Dog 类型的引用 myDog。如果 myAnimal 实际上指向了一个 Dog 对象,那么向下转型将成功,否则将抛出 ClassCastException。

为了安全地进行向下转型,可以使用 instanceof 操作符来检查 myAnimal 是否确实指向了一个 Dog 对象。如果 instanceof 检查为 true,那么向下转型是安全的。


注意:

向上转型后只能调用父类的成员和方法,无法再调用子类特有的成员变量或方法。

一个小坑

避免在调用构造方法时调用已经重写过的方法,否则很容易出错。

如下代码:在实例化子类对象时,我们必须先调用完成父类的构造方法,然而Animal的构造方法又调用了子类的已经重写的方法func,这时发生动态绑定,方法执行重写的func,而此时num的值未完成初始化,就打印了0出来,所以打印结果就如下图:

public class Test {

    public static void main(String[] args) {
        Dog dog=new Dog();

    }
}

class Animal{

public void func(){
    System.out.println("动物");
}

public Animal(){
    func();
}


}


class Dog extends Animal{

    int num=999;
    public void func(){
        System.out.println("狗");
        System.out.println(num);
    }


}

浅谈final关键字

第一:final修饰类,则类不能被继承


第二:修饰类的方法则方法不能被重写

第三:修饰成员变量则变量相当于常量,无法在进行修改。


目录
相关文章
|
4月前
|
算法 Java 程序员
在Java的编程世界里,多态不仅仅是一种代码层面的技术,它是思想的碰撞,是程序员对现实世界复杂性的抽象映射,是对软件设计哲学的深刻领悟。
在Java的编程世界里,多态不仅仅是一种代码层面的技术,它是思想的碰撞,是程序员对现实世界复杂性的抽象映射,是对软件设计哲学的深刻领悟。
74 9
|
4月前
|
Java 开发者
在Java面向对象编程的广阔海洋中,多态犹如一股深邃的潜流,它推动着代码从单一走向多元,从僵化迈向灵活。
在Java面向对象编程的广阔海洋中,多态犹如一股深邃的潜流,它推动着代码从单一走向多元,从僵化迈向灵活。
44 7
|
4月前
|
Java 开发者
那些年,我们一同踏入Java编程的大门,多态,这个充满魔法的名字,曾无数次点亮我们探索面向对象编程的热情。
那些年,我们一同踏入Java编程的大门,多态,这个充满魔法的名字,曾无数次点亮我们探索面向对象编程的热情。
51 5
|
4月前
|
Java 程序员
让我们一起探讨Java多态的奥秘,看看它是如何打破“一刀切”的局限,让我们的代码更加生动多彩
让我们一起探讨Java多态的奥秘,看看它是如何打破“一刀切”的局限,让我们的代码更加生动多彩
43 5
|
4月前
|
Java 程序员
Java中的继承和多态:理解面向对象编程的核心概念
【8月更文挑战第22天】在Java的世界中,继承和多态不仅仅是编程技巧,它们是构建可维护、可扩展软件架构的基石。通过本文,我们将深入探讨这两个概念,并揭示它们如何共同作用于面向对象编程(OOP)的实践之中。你将了解继承如何简化代码重用,以及多态如何为程序提供灵活性和扩展性。让我们启程,探索Java语言中这些强大特性的秘密。
|
2月前
|
存储 Java 测试技术
Java零基础-多态详解
【10月更文挑战第10天】Java零基础教学篇,手把手实践教学!
34 4
|
2月前
|
Java 编译器 程序员
Java多态背后的秘密:动态绑定如何工作?
本文介绍了Java中多态的实现原理,通过动态绑定和虚拟方法表,使得父类引用可以调用子类的方法,增强了代码的灵活性和可维护性。文中通过具体示例详细解析了多态的工作机制。
67 4
|
3月前
|
Java 编译器
封装,继承,多态【Java面向对象知识回顾①】
本文回顾了Java面向对象编程的三大特性:封装、继承和多态。封装通过将数据和方法结合在类中并隐藏实现细节来保护对象状态,继承允许新类扩展现有类的功能,而多态则允许对象在不同情况下表现出不同的行为,这些特性共同提高了代码的复用性、扩展性和灵活性。
封装,继承,多态【Java面向对象知识回顾①】
|
2月前
|
Java
java继承和多态详解
java继承和多态详解
52 5
|
2月前
|
存储 Java 测试技术
Java零基础-多态详解
【10月更文挑战第1天】Java零基础教学篇,手把手实践教学!
30 1