【Java】多态

前言

在 Java 面向对象编程的三大支柱 —— 封装、继承、多态中,多态无疑是最具 “灵活性” 与 “智慧感” 的存在。它如同现实世界中 “同一行为在不同场景下的多样表现”,让代码摆脱了僵化的绑定,呈现出更贴近生活逻辑的动态特性。

1.多态

顾名思义多态,就是多种态度,哈哈哈开玩笑的,在Java中的概念就是不同的对象调用同一个方法,会产生不同的状态。多态的核心思想是:父类引用可以指向子类对象,并且通过这个引用调用方法时,会执行子类重写后的方法(而非父类的方法)。所以说在多态中,只需要弄懂两个概念就可以理解多态,即向上转型方法的重写

2.向上转型

父类的引用引用了子类的对象

2.1向上转型的实现方式

向上转型的实现方式一共有三种,直接赋值方法的传参返回值

class Dog extends Aminal{
    public Dog(String name, int age) {
        super(name, age);
    }

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

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}


class Aminal {
    public String name;
    public int age;

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

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

    @Override
    public String toString() {
        return "Aminal{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

public class Text {

    public static Aminal show1(){
        return new Dog("小夏",21);
    }

    public static void show(Aminal aminal){
        System.out.println(aminal.toString());
    }

    public static void main(String[] args) {
        Aminal aminal = new Dog("旺财", 18);//直接赋值
        System.out.println(aminal.toString());

        show(new Dog("小黄",19));//方法的传参

        Aminal aminal1 = show1();//通过返回值
        System.out.println(aminal1.toString());

    }
}


在这里插入图片描述

注:

  • 如果子类中的方法,父类没有重写的话,通过父类的引用只能调用自己独特的方法,无法调用子类的方法.
  • 向上转型后,若子类重写了父类的方法,通过父类引用调用该方法时,实际执行的是子类重写后的版本(多态的核心体现)。
  • 与方法不同,属性不具备多态性。向上转型后,通过父类引用访问的属性一定是父类中声明的属性,而非子类的同名属性。

3.方法的重写

特点:

  1. 方法名相同
  2. 参数列表相同(数量,类型,顺序)。
  3. 返回值可以不一样,但是两者的返回值必须构成父子关系,除此情况之外,必须一样,否则报错。

3.1 动态绑定

上面那串代码中写了两个重写的方法,eat和toString,在构成向上转型的时候,如果调用的方法是重写的方法,那么在调用该方法的时候,会调用父类的方法,但是实际上是执行子类方法的,这种情况就叫做动态绑定

注:

  • 不能被static所修饰,因为静态的方法是属于类的,不依赖于对象,向上转型后调用的是父类的静态方法
  • 不能被final所修饰,被 final 修饰的方法无法被重写,向上转型后调用的是父类的 final 方法。
  • 重写的时候,子类的限定修饰符必须大于等于父类,否测不能被调用,所以被private修饰的方法,无法被重写。

3.2 静态绑定

典型代表就是重载,在编译的时候,根据用户所传递的实参类型就确定了调用哪个方法。

3.2 向下转型

向下转型是有风险的,因为需要进行强转。如果父类引用指向的是其他类型的对象,强行向下转型会抛出 ClassCastException(类型转换异常)。为了避免 ClassCastException,转型前应使用 instanceof 运算符判断父类引用指向的对象是否为目标子类类型。

public class Text{
    public static void main(String[] args) {
        Aminal aminal = new Dog("小黄",21);
        Aminal aminal = new Cat("小雪",23);
        if (animal instanceof Dog) {
       		 Dog dog = (Dog)aminal;
		} else {
		    System.out.println("无法转换为Dog类型");
		}
    }
}

4.再讲多态

父类引用的对象不同,但调用同一个方法,此时表现出不同的行为,就叫做多态

注:

  • 必须在继承的体系之下
  • 子类必须要对父类方法进行重写
  • 通过父类的引用调用重写的方法

4.1 多态的优缺点

优点:

  1. 提高代码的可扩展性。
  2. 降低代码耦合度。
  3. 简化代码维护 。
  4. 支持动态绑定。
  5. 降低了代码的“圈复杂度”,避免了多次调用大量的if-else。(一段代码中条件语句和循环语句的个数就叫做“圈复杂度”)。

缺点:

  1. 性能略有损耗。
  2. 调试难度增加。
  3. 限制访问子类特有功能。
  4. 过度设计可能导致逻辑混乱。
  5. 属性没有多态性。

5.重写和重载的区别(面试题)

5.1重写

定义:子类和父类中间都具有的方法

特点:

  1. 重写的方法名,子类和父类必须一样
  2. 重写的方法的参数列表必须一样,包含参数个数参数类型参数顺序
  3. 重写方法的返回值基本上都是一样的,除了返回值是有父子关系的

要求:

  1. 不能被finalstatic所修饰
  2. 子类的访问权限必须大于等于父类的访问权限
  3. 被private修饰的方法不可以被重写

5.2重载

定义:方法名一致,返回值和参数列表必须不一样,当然两者取一即可

5.3重写和重载的区别

重写的方法名、参数列表和返回值(除返回值具有父子关系之外)必须一样,重载的方法名保持一致即可,返回值和参数必须不一致,一样会报错。

### Java 多态的概念 Java 中的多态是指同一个接口或类可以有多种不同的实现方式。它允许程序在运行时决定调用哪个方法,从而提高代码的灵活性和可扩展性。多态的核心机制依赖于继承、重写以及动态绑定。 #### 动态绑定 当子类覆盖父类的方法时,在运行期间会根据对象的实际类型来决定执行哪一个版本的方法[^1]。这是多态的关键特性之一。 ### 实现多态的方式 Java多态可以通过以下两种主要形式实现: 1. **方法重写(Override)** 2. **接口实现** 以下是具体示例说明如何利用 `instanceof` 运算符避免潜在异常并展示多态的应用场景。 --- ### 示例代码:Java 多态的具体应用 下面是一个完整的例子,展示了如何通过多态性和 `instanceof` 来处理不同类型的对象实例。 ```java // 定义一个基类 Animal class Animal { void makeSound() { System.out.println("Some generic sound"); } } // 子类 Dog 继承自 Animal 并重写了 makeSound 方法 class Dog extends Animal { @Override void makeSound() { System.out.println("Bark"); } // 额外的功能只属于狗 void fetchStick() { System.out.println("Fetching stick..."); } } // 子类 Cat 继承自 Animal 并重写了 makeSound 方法 class Cat extends Animal { @Override void makeSound() { System.out.println("Meow"); } // 额外的功能只属于猫 void climbTree() { System.out.println("Climbing tree..."); } } public class PolymorphismExample { public static void main(String[] args) { // 创建多个动物对象并通过向上转型存储它们 Animal myDog = new Dog(); Animal myCat = new Cat(); // 调用各自的 makeSound 方法 myDog.makeSound(); // 输出 Bark myCat.makeSound(); // 输出 Meow // 如果需要访问特定子类功能,则需使用 instanceof 和强制转换 if (myDog instanceof Dog) { ((Dog) myDog).fetchStick(); // 正确调用了 Dog 类中的特有方法 } if (myCat instanceof Cat) { ((Cat) myCat).climbTree(); // 正确调用了 Cat 类中的特有方法 } Object cValue = 42; // 假设我们有一个未知类型的变量 // 判断其实际类型并打印相应消息 System.out.println("The type of value is " + (cValue instanceof Double ? "Double" : (cValue instanceof Integer ? "Integer" : "Unknown"))); // 输出 Integer [^2] } } ``` 上述代码片段中: - 我们定义了一个通用的 `Animal` 类作为超类。 - 然后创建两个派生类 `Dog` 和 `Cat`,分别实现了自己的行为逻辑。 - 在主函数里演示了即使将这些对象赋给更广泛的父类引用 (`Animal`),仍然能够正确表现出各自的行为特征——这就是所谓的“编译看声明类型, 执行找真实类型”。 另外还加入了关于 `instanceof` 关键字使用的部分,用于确认某个对象的确切类别以便安全地进行向下造型操作而不会引发 ClassCastException 错误。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yalemandy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值