Java中将一个方法调用同一个方法主体关联起来被称作绑定

绑定分为前期绑定和后期绑定。前期绑定是在编译器决定的,而后期绑定是在程序运行时决定的。Java中除了static方法和final方法(private方法也是final方法,仅仅只是是隐式的为final)之外,其它全部的方法都是后期绑定。Java类的多态指的是当将子类向上转型为父类型并调用父类型中对应的方法时,多态机制会依据动态绑定自己主动推断出调用对应的子类的方法。也就是说多态机制的存在的基础是子类实现了对父类中对应方法的函数覆盖。比方有一个Shape类。该类有一个draw方法。并有Circle、Triangle、Square这三个类均继承自Shape类,而且都重写了父类的draw方法,代码例如以下所看到的:

class Shape{
void draw(){
System.out.println("Draw Shape");
}
} class Circle extends Shape{
void draw(){
System.out.println("Draw Circle");
}
} class Triangle extends Shape{
void draw(){
System.out.println("Draw Triangle");
}
} class Square extends Shape{
void draw(){
System.out.println("Draw Square");
}
} public class Test { public static void main(String[] args) {
Shape[] shapes = {new Circle(), new Triangle(), new Square()};
for(Shape s : shapes){
s.draw();
}
}
}

输出结果为:

Draw Circle
Draw Triangle
Draw Square

我们创建了一个Shapes数组,里面各自是Circle、Triangle和Square的实例,我们在遍历该Shapes数组时事实上已经对其进行了向上转型,即已经模糊了事实上际类型,在遍历Shapes数组时,仅仅知道每一个元素都是一个Shape类型。然后依次调用元素的draw方法。结果没有调用基类Shape的draw方法,而是调用的对象实际子类型中的darw方法,这样的现象就称之为多态。那此处的多态到底是怎么发生的呢?前面说过仅仅要类中的方法不是static和final的,那么该方法是后期绑定也就是在运行时才决定调用主体。在运行s.draw()这句代码时,Java知道了要调用darw方法了。s尽管表面看起来是Shape类型,可是它能推断出s实际上是一个Circle/Triangle/Square类型。这样就将方法的调用主体设置为更为详细的子类,这样就运行了详细子类的draw方法而非父类的draw方法。

我们在看例如以下一段Java代码:

class Shape{
void draw(){
System.out.println("Draw Shape");
} void show(){
draw();
}
} class Circle extends Shape{
void draw(){
System.out.println("Draw Circle");
}
} public class Test {
public static void main(String[] args) {
Shape s = new Circle();
s.show();
}
}

运行结果为:Draw Circle
基类Shape中新增了一个show方法,在show方法中会调用draw方法。当运行代码Shape s = new Circle()时,我们创建了一个Circle类型的实例,并将其向上转型为Shape类型,然后调用基类的show方法。结果基类Shape的show方法调用了子类Circle的draw方法而非基类Shape的draw方法。出现这样的情况的原因还是多态机制。

当运行基类Shape中的show方法时,show方法内部要运行darw方法,darw方法是要运行的方法名,因为draw方法既不是static的,又不是final的。所以draw方法是后期绑定,也就是在运行时推断调用主体。

Java知道s实际上是Circle类型的实例,所以会在基类Shape的show方法中会将子类Circle作为调用主体去调用子类Circle中的draw方法而非基类Shape的draw方法。

那么我们再对上面的样例进行一处改动,我们将基类Shape的draw方法设置为private私有的,代码例如以下:

class Shape{
private void draw(){
System.out.println("Draw Shape");
} void show(){
draw();
}
} class Circle extends Shape{
void draw(){
System.out.println("Draw Circle");
}
} public class Test {
public static void main(String[] args) {
Shape s = new Circle();
s.show();
}
}

运行结果为:Draw Shape

我们再来分析一下原因。

此处还是将子类Circle类型的实例向上转型为基类Shape,在运行基类Shape的show方法时,show方法内要运行draw方法。因为基类Shape中的draw方法被定义为private私有的。而private修饰的方法都实际是final方法(仅仅只是是隐式地修饰为final)。所以基类的draw方法是final的,因为final方法的调用都是前期绑定,也就是final方法的调用是在编译器决定的。所以此处不会发生后期绑定。从而自然运行了基类的draw方法而非子类Circle的draw方法。也能够这样觉得,在我们编写完这个Java文件用IDE对其编译生成class文件时,因为private方法的前期绑定特性,编译器会将Shape中的draw方法的代码都copy到show方法内部。例如以下所看到的:

class Shape{
private void draw(){
System.out.println("Draw Shape");
} void show(){
//编译时将基类draw方法内的代码都copy到show方法中
System.out.println("Draw Shape");
}
}

能够这样理解,在生成的class文件里在show方法中就抹去了draw。仅仅留下copy过来的基类中的draw代码。

此处代码没有运行多态另一个原因是。多态机制的基础是子类对父类进行了函数覆盖。可是在上面的样例中父类Shape中的draw方法被修饰为private的,子类尽管也有一个draw方法,可是这不属于函数覆盖。因为父类中的draw方法为private的,对子类是全然屏蔽的,仅仅有子类覆写了能够訪问的父类中的方法时,才存在函数覆盖一说。所以压根就不存在子类覆盖父类中的private方法一说。既然Circle和Shape之间不存在函数覆盖,那么在在基类Shape的show方法运行draw时就不存在多态调用了。

另一点须要说明的是仅仅有普通的方法调用能够是多态的。字段不是多态的。字段的訪问操作是前期绑定,由编译器解析,所以不是多态的。

此处就不举例了。

Java类的多态机制的更多相关文章

  1. 深度分析:理解Java中的多态机制,一篇直接帮你掌握!

    Java中的多态 1 多态是什么 多态(Polymorphism)按字面的意思就是"多种状态".在面向对象语言中,接口的多种不同的实现方式即为多态.用白话来说,就是多个对象调用同一 ...

  2. java类的反射机制

    1.获得一个类的类对象有哪些方式? - 方法1:类型.class,例如:String.class- 方法2:对象.getClass(),例如:"hello".getClass()- ...

  3. 深入研究Java类装载机制

    目录 1.为什么要研究java类装在机制? 2.了解类装载机制,对于我们在项目开发中有什么作用? 3.装载实现细节. 4.总结 一.为什么药研究Java类装载机制 java类加载机制,便于我们使用自定 ...

  4. Java 类反射机制分析

    Java 类反射机制分析 一.反射的概念及在Java中的类反射 反射主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.在计算机科学领域,反射是一类应用,它们能够自描述和自控制.这类应用通过某 ...

  5. 深入理解Java多态机制

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

  6. java中实现多态的机制是什么?

    多态性是面向对象程序设计代码重用的一个重要机制,我们曾不只一次的提到Java多态性.在Java运行时多态性:继承和接口的实现一文中,我们曾详细介绍了Java实现运行时多态性的动态方法调度:今天我们再次 ...

  7. Java 继承、多态与类的复用

    摘要: 本文结合Java的类的复用对面向对象两大特征继承和多态进行了全面的介绍. 首先,我们介绍了继承的实质和意义,并探讨了继承,组合和代理在类的复用方面的异同.紧接着,我们依据继承引入了多态.介绍了 ...

  8. Java多态机制和继承中重写重载

    关于Java中多态机制 http://www.cnblogs.com/chenssy/p/3372798.html 这篇博文讲的很透彻 大体意思是 多态定义: 多态就是指程序中定义的引用变量所指向的具 ...

  9. 【JAVA】笔记(4)---继承;方法覆盖;多态机制;super;

    继承(extends): 1.作用:为方法覆盖和多态机制做准备:使代码得到复用(节省代码量): 2.格式: class 子类 extends 父类 3.理解继承:子类继承父类,其实就相当于把父类的类体 ...

随机推荐

  1. PCB 电测试--测试点数自动输出到流程指示中(读取TGZ Stephdr文件)

    好不容易实现了 <PCB 无需解压,直接读取Genesis TGZ指定文件 > 正好这里有一项需求:PCB电测试--测试点数自动输出到流程指示中 一.自动输出测试点小结; 1.由于历史原因 ...

  2. nodejs windows环境安装

    相信对于很多关注javascript发展的同学来说,nodejs已经不是一个陌生的词眼.有关nodejs的相关资料网上已经铺天盖地.由于它的高并发特性,造就了其特殊的应用地位. 国内目前关注最高,维护 ...

  3. 2205 等差数列(dp)

    2205 等差数列  时间限制: 1 s  空间限制: 32000 KB  题目等级 : 钻石 Diamond     题目描述 Description 等差数列的定义是一个数列S,它满足了(S[i] ...

  4. 【NOIP2018】 游记

    All ended? [day 0] 一点感觉没有,不过翘掉了早上的课(当然还有前三周的课),然后刚想睡一会儿,就被通知要上车了/难受 在车上玩了一会儿早上下的Super Mario(主要是早上刷了一 ...

  5. 【转载】排名Top 16的Java实用类库

    *转载自HollisChuang 链接:http://www.hollischuang.com/archives/1606 1. org.apache.commons.io.IOUtils close ...

  6. bootstrap 网格布局

    一:基本的网格布局 <div class="container"> <div class="row"> <div class=&q ...

  7. [2月1号] 努比亚全机型ROM贴 最全最新NubiaUI5.0 ROOT 极速体验

    前言 感谢在开发过程中mandfx和dgtl198312予以的帮助!本帖将整理所有Nubia手机的最新刷机包,还有少数机型未制作刷机包,需要的机油可以联系我制作recovery以及刷机包加群23722 ...

  8. OpenCL C

    OpenCL C OpenCL  简介 opencl C是ISO C99的一个扩展,主要区别如下: 去除了C99的一些特性,如:标准C99头文件,函数指针,递归,变长数组,和位域 增加了一些特性用于并 ...

  9. 折纸---珠穆朗玛问题----简单for 循环

    一张纸的厚度大约是0.08mm,对折多少次之后能达到珠穆朗玛峰的高度(8848.13米)? package com.zuoye.test; public class Zhezhi { public s ...

  10. 【PostgreSQL-9.6.3】创建、修改、删除数据库

    1.创建数据库 create database database_name; 2.修改数据库的名称 alter database database_name rename to new_databas ...