开发者社区> 博文视点Broadview> 正文

码出高效:Java开发手册-第2章(9)

简介: 本章开始讲解面向对象思想,并以Java 为载体讲述面向对象思想在具体编程语言中的运用与实践。当前主流的编程语言有50 种左右,主要分为两大阵营:面向对象编程与面向过程编程。面向对象编程(Object-Oriented Programming,OOP)是划时代的编程思想变革,推动了高级语言的快速发展和工业化进程。OOP 的抽象、封装、继承、多态的理念使软件大规模化成为可能,有效地降低了软件开发成本、维护成本和复用成本。面向对象编程思想完全不同于传统的面向过程编程思想,使大型软件的开发就像搭积木一样隔离可控、高效简单,是当今编程领域的一股势不可......
+关注继续查看

2.4.7 覆写

多态中的override,本书翻译成覆写。如果翻译成重写,那么与重构意思过于接近;如果翻译成覆盖,那么少了“写”这个核心动词。如果父类定义的方法达不到子类的期望,那么子类可以重新实现方法覆盖父类的实现。因为有些子类是延迟加载的,甚至是网络加载的,所以最终的实现需要在运行期判断,这就是所谓的动态绑定。动态绑定是多态性得以实现的重要因素,元空间有一个方法表保存着每个可以实例化类的方法信息,JVM 可以通过方法表快速地激活实例方法。如果某个类覆写了父类的某个方法,则方法表中的方法指向引用会指向子类的实现处。代码通常是用这样的方式来调用子类的方法,通常这也被称作向上转型:

Father father = new Son();

// Son 覆写了此方法

father.doSomething();

向上转型时,通过父类引用执行子类方法时需要注意以下两点:

(1)无法调用到子类中存在而父类本身不存在的方法。

(2)可以调用到子类中覆写了父类的方法,这是一种多态实现。

想成功地覆写父类方法,需要满足以下4 个条件:

(1)访问权限不能变小。访问控制权限变小意味着在调用时父类的可见方法无法被子类多态执行,比如父类中方法是用public 修饰的,子类覆写时变成private。设想如果编译器为多态开了后门,让在父类定义中可见的方法随着父类调用链路下来,执行了子类更小权限的方法,则破坏了封装。如下代码所示,在实际编码中不允许将方法访问权限缩小:

class Father {

public void method() {

System.out.println("Father's method");

}

}

class Son extends Father {

// 编译报错,不允许修改为访问权限更严格的修饰符

@override

private void method() {

System.out.println("Son's method");

}

}

(2)返回类型能够向上转型成为父类的返回类型。虽然方法返回值不是方法签名的一部分,但是在覆写时,父类的方法表指向了子类实现方法,编译器会检查返回值是否向上兼容。注意,这里的向上转型必须是严格的继承关系,数据类型基本不存在通过继承向上转型的问题。比如int 与Integer 是非兼容返回类型,不会自动装箱。再比如,如果子类方法返回int,而父类方法返回long,虽然数据表示范围更大,但是它们之间没有继承关系。返回类型是Object 的方法,能够兼容任何对象,包括class、enum、interface 等类型。

(3)异常也要能向上转型成为父类的异常。异常分为checked 和unchecked 两种类型。如果父类抛出一个checked 异常,则子类只能抛出此异常或此异常的子类。而unchecked 异常不用显式地向上抛出,所以没有任何兼容问题。

(4)方法名、参数类型及个数必须严格一致。为了使编译器准确地判断是否是覆写行为,所有的覆写方法必须加@Override 注解。此时编译器会自动检查覆写方法签名是否一致,避免了覆写时因写错方法名或方法参数而导致覆写失败。例如,AbstractCollection 的clear 方法,当覆写此方法时,写成c1ear,注意是数字的1,这会导致定义了两个不同的方法。此外,@Override 注解还可以避免因权限控制可见范围导致的覆写失败。如图2-7 所示,Father 和Son 属于不同的包,它们的method() 方法无权限控制符修饰,是默认仅包内可见的。Father 的method 的方法在Son 中是不可见的。所以,Son 中定义的method 方法是一个“新方法”,如果加上@Override,则会提示:Method does not override method from its superclass。

4.jpg

图2-7 Father 和Son 的覆写关系

综上所述,方法的覆写可以总结成容易记忆的口诀:“一大两小两同”。

  • 一大:子类的方法访问权限控制符只能相同或变大。
  • 两小:抛出异常和返回值只能变小,能够转型成父类对象。子类的返回值、抛出异常类型必须与父类的返回值、抛出异常类型存在继承关系。
  • 两同:方法名和参数必须完全相同。

根据这个原则,再看一个编译和运行都正确的覆写示例代码:

class Father {

protected Number doSomething(int a, Integer b, Object c) throws

SQLException {

System.out.println("Father's doSomething");

return new Integer(7);

}

}

class Son extends Father {

/**

* 1. 权限扩大,由protected 到public(一大)

* 2. 返回值是父类的Number 的子类 (两小)

* 3. 抛出异常是SQLException 的子类

* 4. 方法名必须严格一致 (两同)

* 5. 参数类型与个数必须严格一致

* 6. 必须加@Override

*/

@Override

public Integer doSomething(int a, Integer b, Object c) throws

SQLClientInfoException {

if(a == 0) {

throw new SQLClientInfoException();

}

return new Integer(17);

}

}

覆写只能针对非静态、非final、非构造方法。由于静态方法属于类,如果父类和子类存在同名静态方法,那么两者都可以被正常调用。如果方法有final 修饰,则表示此方法不可被覆写。

如果想在子类覆写的方法中调用父类方法,则可以使用super 关键字。在上述示例代码中,在Son 的doSomething 方法体里可以使用super.doSomething(a,b,c) 调用父类方法。如果与此同时在父类方法的代码中写一句this.doSomething(),会得出什么样的运行结果呢?

public class Father {

protected void doSomething() {

System.out.println("Father's doSomething");

this.doSomething();

}

public static void main(String[] args) {

Father father = new Son();

father.doSomething();

}

}

class Son extends Father {

@Override

public void doSomething() {

System.out.println("Son's doSomething");

super.doSomething();

}

}

在经过了一系列的父子方法循环调用后,JVM 崩溃了,发生了StackOverflowError,如图2-8所示。

5.jpg

图2-8 覆写产生的StackOverflowError

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
高级开发必须理解的Java中SPI机制
高级开发必须理解的Java中SPI机制
25 0
六年Java开发,分享年薪50W+架构师一路成长的辛酸
13年下半年接触java,奇遇一般参加了java培训,期间甘苦自知。14年初如愿找到人生第一份工作,工资3k;对于之前的付出也算是回报吧 ,对于当时的我已经很满足了。 但是后来没想到公司是个坑, 入司半年有余,写的代码屈指可数;但是却结交了一位良师益友对我以后的职业发展和技术上提供了明灯,给予了不少帮助。所以说(塞翁失马,焉知非福)还是有些道理的。
29 0
阿里大牛都在读的10本Java实战书籍,Java开发进阶必备书单
关乎于程序员,除了做项目来提高自身的技术,还有一种提升自己的专业技能就是:多!看!书! 毕竟,书是学习的海洋呢!So,Java程序员你们准备好了吗?双手奉上Java程序员必读之热门书单。
36 0
3分钟教你用java开发一个小程序后台服务器~看完你也会
3分钟教你用java开发一个小程序后台服务器~看完你也会
32 0
一日一技:在Python开发中,如何让Java程序员抓狂
一日一技:在Python开发中,如何让Java程序员抓狂
14 0
【一名资深Java开发的经验浅谈】
【一名资深Java开发的经验浅谈】
31 0
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏21之enemy行走和死亡动画效果
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏21之enemy行走和死亡动画效果
52 0
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏20之enemy被攻击显示后退动画(block效果)
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏20之enemy被攻击显示后退动画(block效果)
39 0
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏19敌人可以被打死
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏19敌人可以被打死
32 0
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏18玩家攻击动画实现
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏18玩家攻击动画实现
37 0
+关注
博文视点Broadview
博文视点( Broadview )是电子工业出版社下属旗舰级子公司。在IT出版领域打磨多年,以敏锐眼光、独特视角密切关注技术发展趋势及变化,致力于将技术大师之优秀思想、一线专家之一流经验集结成书,为众多朋友奉献经典著作,助力个人、团队成长。
文章
问答
视频
文章排行榜
最热
最新
相关课程
更多
相关电子书
更多
JAVA开发手册1.5.0
立即下载
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
相关实验场景
更多