【Thinking in Java】编写构造器时应注意:尽量避免调用其他非private方法
最近重温了《Thinking in Java》,发现了一个让我为之兴奋的知识漏洞,必须得分享一下。
上一篇的《Java类初始化的过程》的随笔中,那个初始化顺序并不完整。初始化的实际过程是:
- 在其他任何事物发生之前,将分配给对象的存储空间初始化成二进制的0;
- 如上一篇的《Java类初始化的过程》那样:父类的static成员变量和方法-->该类的static变量和方法-->开始实例化-->父类的普通成员变量和方法-->父类的构造方法-->该类的普通成员变量和方法-->该类的构造方法-->实例化结束
然而,我们知道,当子类Sub继承了父类Sup、并重写了父类的方法draw()后,我们即使向上转型为父类(即Sup sup=new Sub()),当我们调用sup.draw()方法的时候,它实际上调用的是Sub的draw方法。这里就有个坑了!
如果在父类的构造方法里调用draw()方法,从逻辑上,我们以为是调用父类的draw()方法,而实际上,即使在父类的构造器以内,Java编译器让它调用的还是子类的draw()方法。
我们用一个例子来展示一下:
public class Glyph {
Glyph(){
System.out.println("Glyph before draw()");
draw(); //逻辑上本应该调用本类的draw(),然而结果不是
System.out.println("Glyph after draw()");
}
void draw(){
System.out.println("Glyph.draw()");
}
} public class RoundGlyph extends Glyph{
private int radius=1;
public RoundGlyph(int r) {
radius=r;
System.out.println("RoundGlyph.RoundGlyph(),radius="+radius);
} @Override
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
看打印的第二行,逻辑上我们打印的本应该是Glyph.draw(),然而它被子类覆盖了。而且,就算打印的是RoundGlyph.draw(),radius=0,那radius应该等于1才对啊!不是的,按照类的初始化顺序,先初始化的是父类Glyph的构造器,然后才轮到初始化RoundGlyph的成员变量radius。之所以radius=0,是因为Java类的加载机制的准备阶段,即在用户初始化变量之前,就已经为变量初始化为0了,关于Java虚拟机的类加载机制,可以看下《深入理解Java虚拟机》一书的第7章。
这种bug很难查找,但是又会破坏程序本身,让我们忘bug兴叹。
所以我们在对构造器进行初始化的时候,要尽量简单,尽量避免在构造方法内调用其他public的非构造方法(private方法可以调用,因为它不可被继承)。
【Thinking in Java】编写构造器时应注意:尽量避免调用其他非private方法的更多相关文章
- 原!! java直接打印一个对象时,并不是直接调用该类的toString方法 ,而是会先判断是否为null,非null才会调用toString方法
网上看了好多java直接打印一个对象时,直接调用该类的toString方法 . 但是: Object obj=null; System.out.println(obj);//没有报错 System.o ...
- [Xcode 实际操作]八、网络与多线程-(18)PerformSelector消息处理方法:由运行时系统,负责去调用对象的指定方法
目录:[Swift]Xcode实际操作 本文将演示PerformSelector消息处理方法. 在项目文件夹上点击鼠标右键弹出文件菜单. [New File]->[Swift File]-> ...
- java中main函数怎么调用外部非static方法
使用外部方法时(不管是static还是非static),都要先new一个对象,才能使用该对象的方法. 举例如下: 测试函数(这是错误的): public class Test { public sta ...
- java写文件时,输出不完整的原因以及解决方法
在java的IO体系中,写文件通常会用到下面语句 BufferedWriter bo=new BufferedWriter(new FileWriter("sql语句.txt")) ...
- java写文件时,输出不完整的原因以及解决方法close()或flush()
在java的IO体系中,写文件通常会用到下面语句 BufferedWriter bw=new BufferedWriter(new FileWriter("sql语句.txt")) ...
- 【java】子类可以通过调用父类的public方法调用父类的private方法,为什么?
代码1: 打印结果: 代码2: 运行结果: 问题: 代码1中super是父类自己调用自己的add()方法,并在add()方法中调用了私有的del()方法,那为什么打印出来的this是子类? 代码2中t ...
- 《深入理解Java虚拟机》(二)Java虚拟机运行时数据区
Java虚拟机运行时数据区 详解 2.1 概述 本文参考的是周志明的 <深入理解Java虚拟机>第二章 ,为了整理思路,简单记录一下,方便后期查阅. 2.2 运行时数据区域 Java虚拟机 ...
- Java 构造器 遇到多个构造器时要考虑用构建器
静态工厂和构造器有个共同的局限性:它们都不能很好地扩展到大量的可选参数. 当一个类中有若干个必选属性和多个可选属性时,采用重叠构造器模式.JavaBeans模式或者Builder模式,但各有优劣. 当 ...
- Java编程 “提高性能” 应尽力做到
除了新增机器内存外,还应该好好review一下我们的代码,有很多代码编写过于随意化,这些不好的习惯或对程序语言的不了解是应该好好打压打压了. 下面是参考网络资源总结的一些在Java编程中尽可能要做到的 ...
随机推荐
- android ListView子布局中按钮响应点击事件
只需要在子布局的根布局中添加以下属性即可: android:descendantFocusability="blocksDescendants"
- java 线性规划 和lingo 比较
model:max=13*A+ 23*B; 5*A + 15*B <480 ; 4*A + 4 *B <160 ; 35* A + 20 *B <1190 ; end Variabl ...
- form表单reset表格并执行搜索
其中reset() 不需要定义 search():是你执行的搜索的函数 <html> <head> <title>sf</title></head ...
- jquery指index
$(selector).index(element) 获得元素相对于选择器的 index 位置.<ul> <li><a href="#nogo" ...
- iOS基础-NSString及NSMutableString剖析
一.NSString头文件 NSString : NSObject 实现协议: NSCopying/NSMutableCopying/NSSecureCoding 类别: //扩展类别 NSStrin ...
- C语言 断言 总结
转载: http://wenda.so.com/q/1378817559065638?src=140 assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止 ...
- The path to the driver executable must be set by the webdriver.gecko.driver system property
报这个错,是因为你使用了selenium3+Firefox.在selenium3中,使用Firefox,需要添加驱动. 您可以从Github上下载驱动程序下载网址- https://github.c ...
- 02 Apache Solr: 概览 Solr在信息系统架构中的位置
概述: Apache Solr是一个用JAVA语言构建在Apache Lucene项目上的开源的企业级搜索平台.主要特性包含:全文搜索.命中高亮.片段式搜索.实时索引.动态集群.数据库集成. ...
- WCF通过SVCUtil.exe生成客户端代理类和配置文件(转)
WCF服务调用通过两种常用的方式: 1:一种是借助代码生成工具SvcUtil.exe或者添加服务引用的方式. 2:一种是通过ChannelFactory直接创建服务代理对象进行服务调用. 本文只针对通 ...
- des加密解密——java加密,php解密
最近在做项目中,遇到des加密解密的问题. 场景是安卓app端用des加密,php这边需要解密.之前没有接触过des这种加密解密算法,但想着肯定会有demo.因此百度,搜了代码来用.网上代码也是鱼龙混 ...