热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

深入理解Java中的多态性概念及其应用

多态是面向对象编程中的三大核心特性之一,与封装和继承共同构成了面向对象的基础。多态使得代码更加灵活和可扩展,封装和继承则为其提供了必要的支持。本文将深入探讨多态的概念及其在Java中的具体应用,帮助读者全面理解和掌握这一关键知识点。

什么是多态

面向对象的三大特性:封装、继承、多态。从一定角度来看,封装和继承几乎都是为多态而准备的。这是我们最后一个概念,也是最重要的知识点。

多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)

实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。

多态的作用:消除类型之间的耦合关系。

现实中,关于多态的例子不胜枚举。比方说按下 F1 键这个动作,如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;如果当前在 Word 下弹出的就是 Word 帮助;在 Windows 下弹出的就是 Windows 帮助和支持。同一个事件发生在不同的对象上会产生不同的结果。

下面是多态存在的三个必要条件,要求大家做梦时都能背出来!

多态存在的三个必要条件 一、要有继承; 二、要有重写; 三、父类引用指向子类对象。

多态的好处:

1.可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。

2.可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。

3.接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。如图8.3 所示。图中超类Shape规定了两个实现多态的接口方法,computeArea()以及computeVolume()。子类,如Circle和Sphere为了实现多态,完善或者覆盖这两个接口方法。

4.灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。

5.简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。

Java中多态的实现方式:接口实现,继承父类进行方法重写,同一个类中进行方法重载。

一个小题目:继承父类进行方法重写的例子。

(一)相关类

48304ba5e6f9fe08f3fa1abda7d326ab.png

classA ...{

publicString show(D obj)...{

return ("A and D");

}

publicString show(A obj)...{

return ("A and A");

}

}

class B extendsA...{

publicString show(B obj)...{

return ("B and B");

}

publicString show(A obj)...{

return ("B and A");

}

}

class C extendsB...{}

class D extends B...{}

48304ba5e6f9fe08f3fa1abda7d326ab.png

(二)问题:以下输出结果是什么?

48304ba5e6f9fe08f3fa1abda7d326ab.png

A a1 = newA();

A a2 = newB();

B b = newB();

C c = newC();

D d = newD();

System.out.println(a1.show(b)); ① //a1指向的类时A

System.out.println(a1.show(c)); ②

System.out.println(a1.show(d)); ③

System.out.println(a2.show(b)); ④ //a2指向的类时B,B类直接超类是A而且重写了show(A OBJ)。所以当传入的参数是B对象的时候,调用B类从写的方法。

System.out.println(a2.show(c)); ⑤

System.out.println(a2.show(d)); ⑥

System.out.println(b.show(b)); ⑦

System.out.println(b.show(c)); ⑧ //b指向的类是B,而C,D类的直接超类是B所以调用的是show(B OBJ)。

System.out.println(b.show(d)); ⑨

48304ba5e6f9fe08f3fa1abda7d326ab.png

(三)答案

48304ba5e6f9fe08f3fa1abda7d326ab.png

① A and A

② A and A

③ A and D

④ B and A

⑤ B and A

⑥ A and D

⑦ B and B

⑧ B and B

⑨ A and D

48304ba5e6f9fe08f3fa1abda7d326ab.png

接口和抽象类的例子:

对于抽象类和接口,有许多类实现这个接口(或者继承这个抽象类)。 在调用的时候,用父类引用指向子类对象的方法。然后,调用对象的方法,编译器就会自动根据这个对象实际属于哪个实现类, 来调出这个类对于接口或者抽象类的具体实现。

例:

public classAddress {privateString name;public Address(String name){ this.name =name; }public String getName() { returnname; }public void setName(String name) { this.name =name; }

}

定义基类(抽象类):

public abstract classVehicle {abstract voidgo(Address address);

}

//Car对于基类的实现:public class Car extendsVehicle{

@Overridepublic voidgo(Address address){

System.out.println("Car to " +address.getName());

}

}

Plane对于基类的实现:

public class Plane extendsVehicle{

@Overridevoidgo(Address address)

{ System.out.println("Plane to " +address.getName());

}

}

Driver中多态:

public voiddrive(Vehicle v){///多态,父类引用指向子类对象,实际传过来的是抽象类Vehicle的子类,或者实现类,然后编译器会根据具体实现类,来找实现方法。

v.go(new Address("杭州(abstract)")); ///此方法在具体的实现中被重写

}

Test:public static voidmain(String[] args) {

Driver d= newDriver();

d.drive(new Plane()); //实际是Plane对象,则编译器就会找到Plane中,对go的实现 d.drive(new Car());//实际是Car对象,则编译器就会找到Plane中,对go的实现

}

输出结果: Plane to 杭州(abstract) Car to 杭州(abstract)

事实上,这就是多态所起的作用,可以实现控制反转这在大量的J2EE轻量级框架中被用到,比如Spring的依赖注射机制。 (通过注入不同的bean,来得到不同的实现类)

接口与抽象类的区别:

有个概念,但还没有想到具体实现。 对于一些共用的,已经有实现了,可以设计成接口。

上面是抽象类,下面把它转化为接口:

IVehicle.java public interface IVehicle { public void go(Address address); }

CarImpl.java public class CarImpl implements IVehicle{ public void go(Address address) { System.out.println("CarImpl to " +address.getName()); } }

PlameImpl.java public class PlaneImpl implements IVehicle{ public void go(Address address) { System.out.println("PlaneImpl to " + address.getName()); } }

Driver.java 多态之接口 public void driveI(IVehicle v){ v.go(new Address("杭州(interface)")); }

Test.java 用接口实现 d.driveI(new PlaneImpl()); d.driveI(new PlaneImpl());

打印结果: PlaneImpl to 杭州(interface) PlaneImpl to 杭州(interface)

多态的三要素:1.继承  2.重写  3.父类引用指向子类对象

以上就是我目前学习中的总结,如有不足之处,还望多多赐教。



推荐阅读
  • 在多线程并发环境中,普通变量的操作往往是线程不安全的。本文通过一个简单的例子,展示了如何使用 AtomicInteger 类及其核心的 CAS 无锁算法来保证线程安全。 ... [详细]
  • 本教程详细介绍了如何使用 Spring Boot 创建一个简单的 Hello World 应用程序。适合初学者快速上手。 ... [详细]
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 在软件开发过程中,经常需要将多个项目或模块进行集成和调试,尤其是当项目依赖于第三方开源库(如Cordova、CocoaPods)时。本文介绍了如何在Xcode中高效地进行多项目联合调试,分享了一些实用的技巧和最佳实践,帮助开发者解决常见的调试难题,提高开发效率。 ... [详细]
  • 本文是Java并发编程系列的开篇之作,将详细解析Java 1.5及以上版本中提供的并发工具。文章假设读者已经具备同步和易失性关键字的基本知识,重点介绍信号量机制的内部工作原理及其在实际开发中的应用。 ... [详细]
  • 多线程基础概览
    本文探讨了多线程的起源及其在现代编程中的重要性。线程的引入是为了增强进程的稳定性,确保一个进程的崩溃不会影响其他进程。而进程的存在则是为了保障操作系统的稳定运行,防止单一应用程序的错误导致整个系统的崩溃。线程作为进程的逻辑单元,多个线程共享同一CPU,需要合理调度以避免资源竞争。 ... [详细]
  • [转]doc,ppt,xls文件格式转PDF格式http:blog.csdn.netlee353086articledetails7920355确实好用。需要注意的是#import ... [详细]
  • 本文主要探讨了Java中处理ActionEvent事件的接口,以及一些常见的编程问题和解决方案,包括方法重载、成员变量访问、镜片质量检测等。 ... [详细]
  • JComponentJLabel的setBorder前言用例2205262241前言setBorder(Border边框)实现自JComponentjava.awt.Insets ... [详细]
  • 如何在Java中使用DButils类
    这期内容当中小编将会给大家带来有关如何在Java中使用DButils类,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。D ... [详细]
  • 检查在所有可能的“?”替换中,给定的二进制字符串中是否出现子字符串“10”带 1 或 0 ... [详细]
  • poj 3352 Road Construction ... [详细]
  • 在 Java 中,`join()` 方法用于使当前线程暂停,直到指定的线程执行完毕后再继续执行。此外,`join(long millis)` 方法允许当前线程在指定的毫秒数后继续执行。 ... [详细]
  • 本题探讨如何编写程序来计算一个数值的整数次方,涉及多种情况的处理。 ... [详细]
  • 本文详细解析了客户端与服务器之间的交互过程,重点介绍了Socket通信机制。IP地址由32位的4个8位二进制数组成,分为网络地址和主机地址两部分。通过使用 `ipconfig /all` 命令,用户可以查看详细的IP配置信息。此外,文章还介绍了如何使用 `ping` 命令测试网络连通性,例如 `ping 127.0.0.1` 可以检测本机网络是否正常。这些技术细节对于理解网络通信的基本原理具有重要意义。 ... [详细]
author-avatar
li-yuefang_883
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有