博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java拾遗(一):浅析Java子类和父类的实例化顺序 及 陷阱
阅读量:6914 次
发布时间:2019-06-27

本文共 1986 字,大约阅读时间需要 6 分钟。

本文主要介绍Java里经常使用的子类和父类的变量实例化顺序及陷阱,并结合一个Android实例来探讨此问题。日后编程中应尽量避免此陷阱。

首先看以下一段代码:

定义一个虚类Server.java

package org.yanzi.test1;public abstract class Server {	private static final int DEFAULT_PORT = 900;	public Server() {		// TODO Auto-generated constructor stub		int port = getPort();		System.out.println("port = " + port + " DEFAULT_PORT = " + DEFAULT_PORT);	}	protected abstract int getPort();}
然后定义一个子类SimpleServer.java

package org.yanzi.test1;public class SimpleServer extends Server {private int mPort = 100;	public SimpleServer(int port) {		// TODO Auto-generated constructor stub		this.mPort = port;	}	@Override	protected int getPort() {		// TODO Auto-generated method stub		return mPort;	}	}
測试代码:

package org.yanzi.test1;public class Test1 {	/**	 * @param args	 */	public static void main(String[] args) {		// TODO Auto-generated method stub		Server s = new SimpleServer(600);	}}
測试结果:

port = 0 DEFAULT_PORT = 900

在測试代码里,传了一个參数600,我们希望getPort得到也是600,但遗憾的是得到的是一个大大的0!!!出现这个问题是因对Java子类和父类实例化顺序存在模糊,以下来看下其正确顺序:

1、new一个SimpleServer,SimpleServer的构造函数接收參数600;

2、初始化父类Server的静态变量,DEFAULT_PORT赋值为900;

3、为了实例化子类,首先实例化其父类Server。子类有參数的构造中默认包含了super方法,即调用父类的无參构造函数。因此就到了int port = getPort();这一句,调用子类的getPort方法。子类的getPort方法返回mPort,此时mPort还没有赋值,因此还是0.这就是得到大大的0的原因!!!

4、父类初始化完成后,開始初始化子类的实例变量,mPort赋值100;

5、运行子类的构造函数,mPort赋值600;

6、子类实例化完成,对象创建完了!

真相大白了,再做一个測试。将SimpleServer里的实例变量mPort搞成静态变量例如以下:

package org.yanzi.test1;public class SimpleServer extends Server {private static int mPort = 100;	public SimpleServer(int port) {		// TODO Auto-generated constructor stub		this.mPort = port;	}	@Override	protected int getPort() {		// TODO Auto-generated method stub		return mPort;	}	}
測试结果:

port = 100 DEFAULT_PORT = 900

其运行顺序是:

1.第一个步骤同上,SimpleServer接收构造參数600

2.初始化父类的静态代码块,当然包含静态变量,然后初始化子类的静态变量

3.初始化父类的非静态代码,包含非静态的变量等;

4.运行父类的构造函数;

5.初始化子类的非静态代码

6.运行子类的构造函数。

    至此完成,终于的结论就是构造函数越简单越好,不要在构造函数里做太多操作。回过头再来看杂家的前文: 假设把initView()放在父类里,则子类LAYOUT_ID在使用时还会是0.因此即便要用也要将此弄成static类型的。

    本文參考《编写高质量代码:改善Java的151个建议》、、

转载地址:http://dlncl.baihongyu.com/

你可能感兴趣的文章
实现一个简化版的vue-router
查看>>
Flv封装格式
查看>>
Android RecyclerView实现头部悬浮吸顶效果
查看>>
Python网络爬虫(七) 深度爬虫CrawlSpider
查看>>
使用selenium抓取华尔街见闻和新浪财经数据
查看>>
ListView与EditText冲突问题解决
查看>>
接口咋整?前端数据药神来也
查看>>
使用Jenkins自动构建Android应用打包并上传
查看>>
Android 混淆简单入门
查看>>
视口相关单位的应用 —— 别说你懂CSS相对单位
查看>>
说说在 Vue.js 中如何绑定样式(class 或 style)
查看>>
如何优雅地在 Java 8 中处理异常
查看>>
Pandas分类数据详解 | 轻松玩转Pandas(5)
查看>>
由自定义事件到vue数据响应
查看>>
前端模块化:CommonJS,AMD,CMD,ES6
查看>>
React Native 性能优化组件-PureComponent
查看>>
CSS3系列-css3之线性渐变初探
查看>>
没错,这个就是那个面试可能会问的"破题"!
查看>>
Hello World
查看>>
浅谈js中的继承和拷贝(下)
查看>>