Java 特性之多态性

简介: 多态性面向对象(OOP)三大特性:封装、继承、多态。多态(polymorphism)指同一行为具有多种不同表现形式,在面向对象程序设计中表现为同一消息可以根据发送对象的类型不同,做出多种不同的行为。

多态性

面向对象(OOP)三大特性:封装、继承、多态。

多态(polymorphism)指同一行为具有多种不同表现形式,在面向对象程序设计中表现为同一消息可以根据发送对象的类型不同,做出多种不同的行为。

多态的优点

多态性能够从一定程度上消除类型之间的耦合关系,通过统一接口方式,不同类的对象可以直接替换,程序更加灵活,可扩展。

多态存在的三个必要条件

  • 继承
  • 重写
  • 父类引用指向子类对象

多态的实现方式

重写(Override)与重载(Overload)

方法重载(Method Overloading)

方法重载(Method Overloading)允许类具有多个相同名称的方法,但是方法参数列表不同。

重载形式:

case 1: 参数数量变化(有效)

add(int, int)
add(int, int, int)

case 2: 参数数据类型变化(有效)

add(int, int)
add(int, float)

case 3: 参数数据类型顺序变化(有效)

add(int, float)
add(float, int)

bad case 1: 仅改变返回类型(无效)

int add(int, int)
float add(int, int)

Java 方法签名由方法名和其后的参数列表共同决定,仅改变返回类型编译器无法重载。 
方法重载(Method Overloading)允许改变返回类型和存取权限。

方法重载(Method Overloading)式多态性,即方法调用取决于调用时传递的参数(数量、类型、顺序),属于编译时静态多态性。

方法重写(Method Overriding)

方法重写(Method Overriding)允许子类对父类可以访问的方法,实现自定义行为。重写的优点在于,无需修改父类代码即可改变子类继承的方法。

重写形式: 
重写依赖继承,通过父类引用,指向子类对象实现动态多态性。

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

public class Cat extends Animal{
    @Override
    public void sound(){
        System.out.println("Meow");
    }
    
    public static void main(String args[]){
        Animal obj = new Cat();
        obj.sound();
    }
}

输出:

Meow

重写(覆盖)规则

  • 参数列表必须一样,返回类型需要兼容。
  • 不能降低方法的存取权限。
  • static, private, final 标记的方法以及类的构造方法不能被重写覆盖。

静态绑定与动态绑定

多态的类型可以分为运行时和编译时,方法重写(Method Overriding)代表运行时动态多态性,方法重载(Method Overloading)代表编译时静态多态性。

方法调用与方法体的关联称为绑定,有两种类型的绑定:在编译时发生的静态绑定(Static Binding or Early Binding)和在运行时发生的动态绑定(Dynamic Binding or Late Binding)。

static, private, final 标记的方法以及类的构造方法是编译时静态绑定的。因为此类方法无法覆盖,并且类的类型在编译时即可确定。其他非标记的方法可以称为“虚函数”,Java 中其实并没有“虚函数”的概念,所有普通函数(方法)默认都相当于 C++ 的”虚函数”允许覆盖(Override),因此虚函数(virtual method)能够根据运行时的具体对象进行动态绑定实现动态多态性,例如方法重写(Method Overriding)。

静态绑定示例:

class Human{
   public static void walk()
   {
       System.out.println("Human walks");
   }
}
class Boy extends Human{
   public static void walk(){
       System.out.println("Boy walks");
   }
   public static void main( String args[]) {
       /* Reference is of Human type and object is
        * Boy type
        */
       Human obj = new Boy();
       /* Reference is of Human type and object is
        * of Human type.
        */
       Human obj2 = new Human();
       obj.walk();
       obj2.walk();
   }
}

输出:

Human walks
Human walks

声明为 static 的方法不能被重写,但是能够被再次声明。

Static Binding vs Dynamic Binding

  • 静态绑定发生在编译时,而动态绑定发生在运行时。
  • 静态绑定使用的是类信息:类的类型决定调用方法,而动态绑定使用的是对象信息:对象的类型决定调用方法。
  • 方法重载使用静态绑定,而方法重写使用动态绑定。

综合练习

多态示例:

class A {
    public String show(D obj) { // 方法一
        return ("A and D");
    }

    public String show(A obj) { // 方法二
        return ("A and A");
    }
}

class B extends A {
    public String show(B obj) { // 方法三
        return ("B and B");
    }

    public String show(A obj) { // 方法四
        return ("B and A");
    }
}

class C extends B {
}

class D extends B {
}

public class Main {

    public static void main(String[] args) {
        A a1 = new A();
        A a2 = new B();
        B b = new B();
        C c = new C();
        D d = new D();
        System.out.println("1--" + a1.show(b));
        System.out.println("2--" + a1.show(c));
        System.out.println("3--" + a1.show(d));
        System.out.println("4--" + a2.show(b));
        System.out.println("5--" + a2.show(c));
        System.out.println("6--" + a2.show(d));
        System.out.println("7--" + b.show(b));
        System.out.println("8--" + b.show(c));
        System.out.println("9--" + b.show(d));
    }
}

运行结果:

1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D

详细分析:

A、B、C、D 各类继承关系如图所示:

类图

  1. A a1 = new A(); 正常创建对象 a1,涉及函数重载 show(),a1 具有调用方法一 show(D obj) 和方法二 show(A obj) 的能力。
    a1.show(b) 由编译器进行静态绑定(前期绑定)方法二 show(A obj)。
  2. a1.show(c) 由编译器进行静态绑定(前期绑定)方法二 show(A obj)。
  3. a1.show(d) 由编译器进行静态绑定(前期绑定)方法一 show(D obj)。
  4. A a2 = new B(); 多态创建父类引用,指向子类对象,a2 向上转型具有调用 A 类方法一 show(D obj) 和方法二 show(A obj) 的能力,其中子类 B 重写父类 A 的方法二 show(A obj) 为方法四 show(A obj)。记住向上转型存在缺点,即不能调用子类中有,父类没有的方法,如方法三 show(B obj)。
    a2.show(b) 运行时动态绑定(后期绑定)方法四 show(A obj)。
  5. a2.show(c) 运行时动态绑定(后期绑定)方法四 show(A obj)。
  6. a2.show(d) 由编译器进行静态绑定(前期绑定)方法一 show(D obj)。
  7. B b = new B(); 正常创建对象 b,涉及函数重载 show(),b 具有调用方法三 show(B obj) 和方法四 show(A obj) 的能力。同时 B 继承自 A 因此拥有方法一 show(D obj) 和方法二 show(A obj) 其中方法二被方法四重写覆盖。
    b.show(b) 由编译器进行静态绑定(前期绑定)方法三 show(B obj)。
  8. b.show(c) 由编译器进行静态绑定(前期绑定)方法三 show(B obj)。
  9. b.show(d) 由编译器进行静态绑定(前期绑定)方法一 show(D obj)。
目录
相关文章
|
30天前
|
安全 前端开发 Java
随着企业应用复杂度提升,Java Spring框架以其强大与灵活特性简化开发流程,成为构建高效、可维护应用的理想选择
随着企业应用复杂度提升,Java Spring框架以其强大与灵活特性简化开发流程,成为构建高效、可维护应用的理想选择。依赖注入使对象管理交由Spring容器处理,实现低耦合高内聚;AOP则分离横切关注点如事务管理,增强代码模块化。Spring还提供MVC、Data、Security等模块满足多样需求,并通过Spring Boot简化配置与部署,加速微服务架构构建。掌握这些核心概念与工具,开发者能更从容应对挑战,打造卓越应用。
32 1
|
20天前
|
安全 Java API
告别繁琐编码,拥抱Java 8新特性:Stream API与Optional类助你高效编程,成就卓越开发者!
【8月更文挑战第29天】Java 8为开发者引入了多项新特性,其中Stream API和Optional类尤其值得关注。Stream API对集合操作进行了高级抽象,支持声明式的数据处理,避免了显式循环代码的编写;而Optional类则作为非空值的容器,有效减少了空指针异常的风险。通过几个实战示例,我们展示了如何利用Stream API进行过滤与转换操作,以及如何借助Optional类安全地处理可能为null的数据,从而使代码更加简洁和健壮。
53 0
|
2天前
|
机器学习/深度学习 人工智能 安全
python和Java的区别以及特性
Python:适合快速开发、易于维护、学习成本低、灵活高效。如果你需要快速上手,写脚本、数据处理、做点机器学习,Python就是你的首选。 Java:适合大型项目、企业级应用,性能要求较高的场景。它类型安全、跨平台能力强,而且有丰富的生态,适合更复杂和规模化的开发。
12 3
|
9天前
|
安全 Java API
Java 18 概述:新特性一览
Java 18 作为 Java 平台的最新版本,引入了多项令人振奋的新特性和改进,包括模式匹配、记录类型、流库改进、外部函数与内存 API 以及并发处理增强。这些新功能不仅提升了开发者的生产力,还显著增强了 Java 的性能和安全性。本文将详细介绍 Java 18 的主要新特性,并通过代码示例帮助读者更好地理解和应用这些功能。
|
18天前
|
Java API
Java 8新特性:Lambda表达式与Stream API的深度解析
【7月更文挑战第61天】本文将深入探讨Java 8中的两个重要特性:Lambda表达式和Stream API。我们将首先介绍Lambda表达式的基本概念和语法,然后详细解析Stream API的使用和优势。最后,我们将通过实例代码演示如何结合使用Lambda表达式和Stream API,以提高Java编程的效率和可读性。
|
21天前
|
Java 开发者
Java 8新特性之Lambda表达式与函数式接口
【7月更文挑战第59天】本文将介绍Java 8中的一个重要新特性——Lambda表达式,以及与之密切相关的函数式接口。通过对比传统的匿名内部类,我们将探讨Lambda表达式的语法、使用方法和优势。同时,我们还将了解函数式接口的定义和用途,以及如何将Lambda表达式应用于函数式编程。
|
30天前
|
分布式计算 Java API
Java 8带来了流处理与函数式编程等新特性,极大提升了开发效率
Java 8带来了流处理与函数式编程等新特性,极大提升了开发效率。流处理采用声明式编程模型,通过filter、map等操作简化数据集处理,提高代码可读性。Lambda表达式支持轻量级函数定义,配合Predicate、Function等接口,使函数式编程无缝融入Java。此外,Optional类及新日期时间API等增强功能,让开发者能更优雅地处理潜在错误,编写出更健壮的应用程序。
24 1
|
1月前
|
Java API Apache
JDK8到JDK24版本升级的新特性问题之在Java中,HttpURLConnection有什么局限性,如何解决
JDK8到JDK24版本升级的新特性问题之在Java中,HttpURLConnection有什么局限性,如何解决
|
1月前
|
自然语言处理 Java 应用服务中间件
Java 18 新特性解析
Java 18 新特性解析
|
1月前
|
Oracle 安全 Java
JDK8到JDK28版本升级的新特性问题之在Java 15及以后的版本中,密封类和密封接口是怎么工作的
JDK8到JDK28版本升级的新特性问题之在Java 15及以后的版本中,密封类和密封接口是怎么工作的