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. NOI2007项链工厂——sbTreap代码

    #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> ...

  2. Entity Framework Code First -- 延迟加载和预先加载

    还是以这两个表为例子 country包含零个或多个city, 这个外键关系是我后来加上去,原来没有. 然后再用Power Tool逆向, 产生如下代码 1: using System.Componen ...

  3. Android fragment的切换(解决REPLACE的低效)

    在项目中切换Fragment,一直都是用replace()方法来替换Fragment.但是这样做有一个问题,每次切换的时候Fragment都会重新实列化,重新加载一次数据,这样做会非常消耗性能用用户的 ...

  4. div 背景放图和直接放图区别

    <html> <head> <meta charset="UTF-8"> <title></title> <sty ...

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

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

  6. CDC之Metastability

    1 CDC  A clock domain crossing occurs whenever data is transferred from a flop driven by one clock t ...

  7. Hadoop多节点Cluster

    Hadoop多节点集群规划 服务起名称 内网IP HDFS YARN master 192.168.1.155 NameNode ResourceManager slave1 192.168.1.11 ...

  8. 实验8 标准模板库STL

    一.实验目的与要求: 了解标准模板库STL中的容器.迭代器.函数对象和算法等基本概念. 掌握STL,并能应用STL解决实际问题. 二.实验过程: 完成实验8标准模板库STL中练习题,见:http:// ...

  9. react基础篇六

    创建 Refs 使用 React.createRef() 创建 refs,通过 ref 属性来获得 React 元素.当构造组件时,refs 通常被赋值给实例的一个属性,这样你可以在组件中任意一处使用 ...

  10. Dispatch Queues and Thread Safety

    Dispatch Queues and Thread Safety It might seem odd to talk about thread safety in the context of di ...