Java中除了static方法和final方法(private方法本质上属于final方法,因为不能被子类访问)之外,其它所有的方法都是动态绑定,这意味着通常情况下,我们不必判定是否应该进行动态绑定—它会自动发生。

final方法会使编译器生成更有效的代码,这也是为什么说声明为final方法能在一定程度上提高性能(效果不明显)。

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

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 StaticPolymorphism {

public static void main(String[] args) {

StaticSuper sup = new StaticSub();

System.out.println(sup.staticGet());

System.out.println(sup.dynamicGet());

}

}

输出:

Base staticGet()

Derived dynamicGet()

构造函数并不具有多态性,它们实际上是static方法,只不过该static声明是隐式的。因此,构造函数不能够被override。

在父类构造函数内部调用具有多态行为的函数将导致无法预测的结果,因为此时子类对象还没初始化,此时调用子类方法不会得到我们想要的结果。

class Glyph {

void draw() {

System.out.println("Glyph.draw()");

}

Glyph() {

System.out.println("Glyph() before draw()");

draw();

System.out.println("Glyph() after draw()");

}

}

class RoundGlyph extends Glyph {

private int radius = 1;

RoundGlyph(int r) {

radius = r;

System.out.println("RoundGlyph.RoundGlyph(). radius = " + radius);

}

void draw() {

System.out.println("RoundGlyph.draw(). radius = " + radius);

}

}

public class PolyConstructors {

public static void main(String[] args) {

new RoundGlyph(5);

}

}

输出:

Glyph() before draw()

RoundGlyph.draw(). radius = 0

Glyph() after draw()

RoundGlyph.RoundGlyph(). radius = 5

为什么会这样输出?这就要明确掌握Java中构造函数的调用顺序:

(1)在其他任何事物发生之前,将分配给对象的存储空间初始化成二进制0;

(2)调用基类构造函数。从根开始递归下去,因为多态性此时调用子类覆盖后的draw()方法(要在调用RoundGlyph构造函数之前调用),由于步骤1的缘故,我们此时会发现radius的值为0;

(3)按声明顺序调用成员的初始化方法;

(4)最后调用子类的构造函数。

只有非private方法才可以被覆盖,但是还需要密切注意覆盖private方法的现象,这时虽然编译器不会报错,但是也不会按照我们所期望的来执行,即覆盖private方法对子类来说是一个新的方法而非重载方法。因此,在子类中,新方法名最好不要与基类的private方法采取同一名字(虽然没关系,但容易误解,以为能够覆盖基类的private方法)。

Java类中属性域的访问操作都由编译器解析,因此不是多态的。父类和子类的同名属性都会分配不同的存储空间,如下:

// Direct field access is determined at compile time.

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.field;

}

}

public class FieldAccess {

public static void main(String[] args) {

Super sup = new Sub();

System.out.println("sup.filed = " + sup.field +

", sup.getField() = " + sup.getField());

Sub sub = new Sub();

System.out.println("sub.filed = " + sub.field +

", sub.getField() = " + sub.getField() +

", sub.getSuperField() = " + sub.getSuperField());

}

}

输出:

sup.filed = 0, sup.getField() = 1

sub.filed = 1, sub.getField() = 1, sub.getSuperField() = 0

Sub子类实际上包含了两个称为field的域,然而在引用Sub中的field时所产生的默认域并非Super版本的field域,因此为了得到Super.field,必须显式地指明super.field。

刚学面向对象的多态性,大部分人是理解不深,甚至无法理解的状态,这不怪你,只是你没有明白,想要完全理解多态性,不仅需要大量的代码积累,还要对面向对象的思想有一段时间的消化,所以刚看这本书的初学者会非常苦恼,完全不懂,没有关系,当你学完扣丁的Java核心技术视频后,也就适合看这本书的时候了,你将会有不一样的收获。

《Java编程思想》之重点笔记——多态性理解的更多相关文章

  1. 《Java编程思想》阅读笔记二

    Java编程思想 这是一个通过对<Java编程思想>(Think in java)进行阅读同时对java内容查漏补缺的系列.一些基础的知识不会被罗列出来,这里只会列出一些程序员经常会忽略或 ...

  2. 《Java编程思想》读书笔记(二)

    三年之前就买了<Java编程思想>这本书,但是到现在为止都还没有好好看过这本书,这次希望能够坚持通读完整本书并整理好自己的读书笔记,上一篇文章是记录的第一章到第十章的内容,这一次记录的是第 ...

  3. 《Java编程思想》读书笔记(四)

    前言:三年之前就买了<Java编程思想>这本书,但是到现在为止都还没有好好看过这本书,这次希望能够坚持通读完整本书并整理好自己的读书笔记,上一篇文章是记录的第十七章到第十八章的内容,这一次 ...

  4. 《Java编程思想》读书笔记(五)

    前言:本文是<Java编程思想>读书笔记系列的最后一章,本章的内容很多,需要细读慢慢去理解,文中的示例最好在自己电脑上多运行几次,相关示例完整代码放在码云上了,码云地址:https://g ...

  5. 《Java编程思想》读书笔记

    前言 这个月一直没更新,就是一直在读这本<Java编程思想>,这本书可以在Java业界被传神的一本书,无论谁谈起这本书都说好,不管这个人是否真的读过这本书,都说啊,这本书很好.然后再看这边 ...

  6. 《Java编程思想》学习笔记_多态

    多态 多态指一个行为产生多种状态,针对父类类型可接收其子类类型,最终执行的状态由具体子类确定,其不同子类可呈现出不同状态.例如人[父类]都会跑步[行为],但小孩[子类]跑步.成年人[子类]跑步.运动员 ...

  7. 《Java编程思想》读书笔记(三)

    前言:三年之前就买了<Java编程思想>这本书,但是到现在为止都还没有好好看过这本书,这次希望能够坚持通读完整本书并整理好自己的读书笔记,上一篇文章是记录的第十一章到第十六章的内容,这一次 ...

  8. 《Java编程思想》学习笔记(二)——类加载及执行顺序

    <Java编程思想>学习笔记(二)--类加载及执行顺序 (这是很久之前写的,保存在印象笔记上,今天写在博客上.) 今天看Java编程思想,看到这样一道代码 //: OrderOfIniti ...

  9. java 方法调用绑定--《java编程思想》学习笔记

    将一个方法调用同一个方法主体关联起来,就是绑定. 绑定分两种 :前期绑定 和 后期绑定 . 绑定------------- | -----前期绑定-------编译期绑定 { static , fin ...

  10. 《java编程思想》读书笔记(一)开篇&第五章(1)

    2017 ---新篇章  今天终于找到阅读<java编程思想>这本书方法了,表示打开了一个新世界. 第一章:对象导论 内容不多但也有20页,主要是对整本书的一个概括.因为已经有过完整JAV ...

随机推荐

  1. angularJS中如何写控制器

    angularJS中的控制器是一个函数,用来向视图作用域中添加额外的功能,我们用它来给作用域对象设置初始状态,并添加自定义行为 当我们在页面上创建一个新的控制器时,angularJS会生成并传递一个新 ...

  2. mysql hash索引优化

    创建表 CREATE TABLE `t1` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `msg` varchar(20) NOT NULL DEFAULT ' ...

  3. Nginx源码研究八:nginx监听socket实现流程

    前面描述了nginx系统分析nginx的配置文件,初始化模块相关参数的过程,这里利用nginx监听socket的实现过程,做一次完整的回顾 1.首先,nginx启动的main函数中,会先初始化cycl ...

  4. matplotlib入门--1(条形图, 直方图, 盒须图, 饼图)

    作图首先要进行数据的输入,matplotlib包只提供作图相关功能,本身并没有数据读入.输出函数,针对各种试验或统计文本数据输入可以使用numpy提供的数据输入函数. # -*- coding: gb ...

  5. Python 可变对象和不可变对象

    具体可以看这里:http://thomaschen2011.iteye.com/blog/1441254 不可变对象:int,string,float,tuple 可变对象   :list,dicti ...

  6. UITableView的详细使用

    UITableView的详细使用   UITableView是app开发中常用到的控件,功能很强大,多用于数据的显示.下面以一个简单的实例来介绍tableview的基本用法.(适合新手,高手飘过) @ ...

  7. VM虚拟机上 实现CentOS 6.X下部署LVS(DR)+keepalived实现高性能高可用负载均衡

    一.简介 LVS是Linux Virtual Server的简写,意即Linux虚拟服务器,是一个虚拟的服务器集群系统.本项目在1998年5月由章文嵩博士成立,是中国国内最早出现的自由软件项目之一. ...

  8. javascript book

    我们很欣喜地看到,在设计模式领域,<JavaScript设计模式>(JavaScript Design Patterns)和<JavaScript编程模式>(JavaScrip ...

  9. Excel进行项目规划的好处

    1.表格的方式 2.多个工作表 3.插入图片 4.清晰的规划 5.大众都能看得懂 6.辅助一些数据表设计,其他的流程设计 7.对项目该做什么,进度等等有一个明确的认识 8.项目管理,吃透需求,对进度把 ...

  10. POJ1088 滑雪(记忆化搜索)

    题目链接. 分析: 状态转移方程 d[i][j] = max(d[i-1][j], d[i+1][j], d[i][j-1], d[i][j+1]). #include <iostream> ...