前言

在面向对象程序设计语言中,多态是继数据抽象和继承之后的第三种基本特性。多态的含义是什么,有什么作用以及在Java中是怎么实现的?下面将做介绍。

什么是多态

简单点说就是“一个接口,多种实现”,不同类对同一操作体现出不同效果。设想有一个性质,一个引用变量所指向的确切类型和该引用变量调用的方法是哪个类中的,这个两个问题在编译期间是不确定的,在程序运行期间才可确定。于是,一份代码就可以适用于多个不同的类,只要这份代码中有一个引用变量可以指向这些不同的类的对象。在程序运行期间,就可以动态选择多个不同的对象或者多个不同的方法运行,这就是多态性

也可以简单的使用Java核心卷中的一句话说:一个引用变量可以指示多种实际类型的现象被称为多态。

要什么样的引用变量才可以指向多种不同类的对象呢?那就需要是基类引用变量。这就涉及到向上转型

向上转型

简单一句话就是:基类(父类)引用指向子类对象。取这个术语属于也是有历史原因的,以传统的类继承图的绘制方法为基础:将根置于页面的顶端,然后逐渐向下。

为什么基类引用就可以指向子类对象呢?

这可以以生活中的一个例子来说,狗是对所有品种狗的统称,具体的品种又有哈士奇,拉布拉多犬等。假设我们在路上遇见了一只不知道名字的狗(比如牧羊犬),我们也许会说:那儿有一只狗。此时,我们就做了向上转型,以狗指向了具体的牧羊犬。以范围较大的基类引用去指向范围小的子类。这是以生活中的例子解释,在语言层面其实也可以说明:子类是继承基类而来,所以基类中的所有方法子类也有,可以发送给基类的消息同样也可以发送给子类。使用基类引用也就可以指向子类对象调用这些方法。

可以使用基类引用指向子类对象,那么可不可以使用子类引用指向基类对象呢?

是可以的,这就叫做向下转型,但是这存在风险。因为子类中可能会有新增方法,而基类中是没有这些方法的,若是调用这些方法就会抛出ClassCastException异常。

介绍了什么是多态,那么就了解它的作用有什么。

多态的作用

多态的一个好处就是可以实现统一管理,需要注意父类不能调用子类特有的方法即父类中没有的方法子类有的方法,若要调用需要向下转型。

多态如何实现

Java中实现多态的三个要求为:

  • 要有继承关系

  • 方法要被重写

  • 基类引用指向子类对象

可以看一个简单的多态例子

class Animal{
public void eat() { System.out.println("吃东西"); }
} class Dog extends Animal{
public void eat() { System.out.println("吃狗粮");}
} class Cat extends Animal{
public void eat() { System.out.println("吃小鱼干");}
} public class PloyTest {
//使用父类引用指向子类对象 调用子类中被重写的方法
public static void printEatingFood(Animal a) { a.eat();} public static void main(String[] args) {
printEatingFood(new Dog());
printEatingFood(new Cat());
}
}
/*
output:
吃狗粮
吃小鱼干
*/

当我们传入Dog对象时,a.eat()调用的是Dog类中被重写的eat方法;传入Cat对象时,a.eat()调用的是Cat类中被重写的方法。程序在运行过程中,依据我们传入的对象自动地为我们寻找到正确的方法调用。这就是多态技术的实现依据:动态绑定。

动态绑定

《Java编程思想》上这样说:运行时父类引用根据其指向的对象,绑定到相应的对象方法上。

那么这个过程的具体实现是怎样的呢?《Java核心技术卷1》上是这样解释的解释:

先是要清楚调用对象方法的过程:

  1. 搜索过程)编译器查看对象的声明类型和方法名。可能会有同名的重载方法。

若是调用x.f(param)

获得当前类和超类中为public的名为f的方法,即获可能被调用的候选方法

  1. 匹配过程)然后,编译器查看调用方法时提供的参数类型,与候选方法进行匹配,此过程也就是重载解析。

完全匹配,则选择调用该方法,这其中还会存在类型转换,所以过程会比较复杂。最后若是没有找到匹配的,编译器则会报错。

​ -------------------------------------------------------------------------------------------

静态绑定:
若方法是private, static, final或者构造器,那么编译器会知道调用哪个方法,这种方式为静态绑定。

动态绑定:
依赖于隐式参数的实际类型,在运行时才可以确定调用方法,则为动态绑定。
当程序运行,并且采用动态绑定调用方法时,虚拟机会调用与x所引用对象的实际类型最合适的那个类的方法。并且为了避免每次搜索浪费时间,虚拟机会为每个类创建一个方法表。其中包含所有方法的签名和实际调用的方法(包括继承来方法)。

一些陷阱和建议

域和静态方法

我们需要注意只有普通方法调用才可以是多态的,对域的访问将在编译时期进行解析。如下面这个例子:

class Super{
public int field = 0;
public int getField() { return field;}
} class Sub extends Super{
public int field = 1;
public int getField() { return field;}
public int getSuperField() { return super.getField();}
} public class FieldAccess {
public static void main(String[] args) {
Super sup = new Sub();
System.out.println("sup.field="+sup.field+" sup.getField()="+sup.getField()); Sub sub = new Sub();
System.out.println("sub.getField="+sub.field+" sub.getField()="+sub.getField()+
" sub.getSuperField()="+sub.getSuperField());
}
}
/*
output:
sup.field=0 sup.getField()=1
sub.getField=1 sub.getField()=1 sub.getSuperField()=0
*/

当使用父类Super的引用sup指向子类Sub类对象,输出域,发现是父类的值。因此,域的访问是编译器解析,不是多态的。

如果某个方法是静态的,它的行为也不具有多态性

class StaticSuper{
public static String staticGet() {
return "Base staticGet()";
} public String dynamicGet(){
return "Base dynamicGet()";
}
} class StaticSub extends StaticSuper{
public static String staticGet() {
return "Derived staticGet()";
} public String dynamicGet() {
return "Derived dynamicGet()";
}
} public class OverloadingTest {
public static void main(String[] args) {
StaticSuper sup = new StaticSub(); //向上转型
System.out.println(sup.staticGet());
System.out.println(sup.dynamicGet());
}
}
/*
output:
Base staticGet()
Derived dynamicGet()
*/

由输出可以看出,静态方法是不具有多态性的。静态方法是与类,而非与单个的对象相关联的。

小结

简要介绍了对于多态的理解,其中存在的不足,希望各位看官不吝赐教。

参考:

《Java编程思想》第四版

《Java核心技术卷1》第九版

Java多态性理解,好处及精典实例:https://blog.csdn.net/Jian_Yun_Rui/article/details/52937791

Java——多态浅析的更多相关文章

  1. Java 多态——与C++的比较

    学习了Java和C++之后,由于长期不使用C++,而java的基础知识掌握不牢,现在已经搞不清java多态了.现在先来谈谈java多态,稍后有时间再更新C++的多态,并进行比较~ 一. Java的多态 ...

  2. C++和java多态的区别

    C++和java多态的区别 分类: Java2015-06-04 21:38 2人阅读 评论(0) 收藏 举报  转载自:http://www.cnblogs.com/plmnko/archive ...

  3. 深入理解Java多态机制

    从字节码层面来看,Java中的所有方法调用,最终无外乎转换为如下几条调用指令. invokestatic: 调用静态方法. invokespecial: 调用实例构造器<init>方法,私 ...

  4. Java 多态 父类和子类方法的访问控制权限

    Java 多态 父类和子类方法的访问控制权限 @author ixenos 父类和子类方法的访问控制权限 继承是为了扩展类的功能,而这种扩展显然就是对一个原始类的扩展,目的还是向上转型来调用,所以这就 ...

  5. Java多态(二)

    public class ExtendsTest { public static void main(String[] args) { A a1 = new A(); A a2 = new B(); ...

  6. 从JVM角度看Java多态

    首先,明确一下,Java多态的三个必要条件: 1. 继承 2. 子类重写父类方法 3. 父类引用指向子类对象 然后看一个例子 package test.xing; class Father{ prot ...

  7. 关于java多态的理解

    要理解多态,就必须有一个大的理解方向,不然很容易绕进去. 首先知道多态的释义:多态性是指一个名词可以有多种语义. 对于java的多态性学习者来说,就是必须要知道多个同名方法在不同情况下的使用规则. j ...

  8. Java经验杂谈(2.对Java多态的理解)

    多态是面向对象的重要特性之一,我试着用最简单的方式解释Java多态: 要正确理解多态,我们需要明确如下概念:・定义类型和实际类型・重载和重写・编译和运行 其中实际类型为new关键字后面的类型. 重载发 ...

  9. 学JAVA第十六 天,JAVA多态

    今天老师讲了多态的使用 多态是同一个行为具有多个不同表现形式或形态的能力. 多态的优点: 1. 消除类型之间的耦合关系 2. 可替换性  3. 可扩充性 4. 接口性 5. 灵活性 6. 简化性 我个 ...

随机推荐

  1. 3.jmeter接口测试---脚本录制

    安装好jmeter后,就要进入主题了,进行接口测试,接口测试的脚本获取方式 ①手动填写 ②badboy录制后,导入jmeter使用 ③jmeter录制 不会安装的可以进入这里:https://www. ...

  2. HDP Hive StorageHandler 下推优化的坑

    关键词:hdp , hive , StorageHandler 了解Hive StorageHandler的同学都知道,StorageHandler作为Hive适配不同存储的拓展类,同时肩负着Hive ...

  3. 10. vue axios 请求未完成时路由跳转报错问题

    axios 请求未完成时路由跳转报错问题 前两天项目基本功能算是完成了,在公司测试时遇到了遇到了一个问题,那就是在请求未完成时进行路由跳转时会报错,想了几种办法来解决,例如加loading,请求拦截, ...

  4. java从pdf中提取文本

    一(单文件转换):下载pdfbox包,百度搜pdfbox.(fontbox-1.8.16.jar和pdfbox-app-1.8.16.jar) package pdf; import java.io. ...

  5. spring boot 集成 Redis

    前提:你已经安装了Redis 1.创建一个spring boot 工程 2.pom 引入依赖:spring-boot-starter-data-redis <dependency> < ...

  6. 实战经验丨PHP反序列化漏洞总结

    又到了金三银四跳槽季,很多小伙伴都开始为面试做准备,今天小编就给大家分享一个网安常见的面试问题:PHP反序列化漏洞. 虽然PHP反序列化漏洞利用的条件比较苛刻,但是一旦被利用就会产生很严重的后果,所以 ...

  7. [Swift]LeetCode247.对称数 II $ Strobogrammatic Number II

    A strobogrammatic number is a number that looks the same when rotated 180 degrees (looked at upside ...

  8. [Swift]LeetCode251.展平二维向量 $ Flatten 2D Vector

    Implement an iterator to flatten a 2d vector. For example,Given 2d vector = [ [1,2], [3], [4,5,6] ] ...

  9. [Swift]LeetCode641. 设计循环双端队列 | Design Circular Deque

    Design your implementation of the circular double-ended queue (deque). Your implementation should su ...

  10. WebView 讲义

    http://reezy.me/p/20170515/android-webview/  (比较全面) 参考 https://developer.android.com/reference/andro ...