建议34: 构造函数尽量简化

我们知道在通过new关键字生成对象时必然会调用构造函数,构造函数的简繁情况会直接影响实例对象的创建是否繁琐。在项目开发中,我们一般都会制订构造函数尽量简单,尽可能不抛异常,尽量不做复杂算法等规范,那如果一个构造函数确实复杂了会怎么样?我们来看一段代码:

 1 public class Client {
 2     public static void main(String[] args) {
 3         Server s = new SimpleServer(1000);
 4     }
 5 }
 6
 7 // 定义一个服务
 8 abstract class Server {
 9     public final static int DEFAULT_PORT = 40000;
10
11     public Server() {
12         // 获得子类提供的端口号
13         int port = getPort();
14         System.out.println("端口号:" + port);
15         /* 进行监听动作 */
16     }
17
18     // 由子类提供端口号,并做可用性检查
19     protected abstract int getPort();
20 }
21
22 class SimpleServer extends Server {
23     private int port = 100;
24
25     // 初始化传递一个端口号
26     public SimpleServer(int _port) {
27         port = _port;
28     }
29
30     // 检查端口号是否有效,无效则使用默认端口,这里使用随机数模拟
31     @Override
32     protected int getPort() {
33         return Math.random() > 0.5 ? port : DEFAULT_PORT;
34     }
35 }

该代码是一个服务类的简单模拟程序,Server类实现了服务器的创建逻辑,子类只要在生成实例对象时传递一个端口号即可创建一个监听该端口的服务,该代码的意图如下:

通过SimpleServer的构造函数接收端口参数。

子类的构造函数默认调用父类的构造函数。

父类构造函数调用子类的getPort方法获得端口号。

父类构造函数建立端口监听机制。

对象创建完毕,服务监听启动,正常运行。

貌似很合理,再仔细看看代码,确实也和我们的意图相吻合,那我们尝试多次运行看看,输出结果要么是“端口号:40000”,要么是“端口号:0”,永远不会出现“端口号:100”或是“端口号:1000”,这就奇怪了,40000还好说,但那个0是怎么冒出来的呢?代码在什么地方出现问题了?

要解释这个问题,我们首先要说说子类是如何实例化的。子类实例化时,会首先初始化父类(注意这里是初始化,可不是生成父类对象),也就是初始化父类的变量,调用父类的构造函数,然后才会初始化子类的变量,调用子类自己的构造函数,最后生成一个实例对象。了解了相关知识,我们再来看上面的程序,其执行过程如下:

子类SimpleServer的构造函数接收int类型的参数:1000。

父类初始化常变量,也就是DEFAULT_PORT初始化,并设置为40000。

执行父类无参构造函数,也就是子类的有参构造中默认包含了super()方法。

父类无参构造函数执行到“int port = getPort()”方法,调用子类的getPort方法实现。

子类的getPort方法返回port值(注意,此时port变量还没有赋值,是0)或DEFAULT_PORT(此时已经是40000)了。

父类初始化完毕,开始初始化子类的实例变量,port赋值100。

执行子类构造函数,port被重新赋值为1000。

子类SimpleServer实例化结束,对象创建完毕。

终于清楚了,在类初始化时getPort方法返回的port值还没有赋值,port只是获得了默认初始值(int类的实例变量默认初始值是0),因此Server永远监听的是40000端口了(0端口是没有意义的)。这个问题的产生从浅处说是由类元素初始化顺序导致的,从深处说是因为构造函数太复杂而引起的。构造函数用作初始化变量,声明实例的上下文,这都是简单的实现,没有任何问题,但我们的例子却实现了一个复杂的逻辑,而这放在构造函数里就不合适了。

问题知道了,修改也很简单,把父类的无参构造函数中的所有实现都移动到一个叫做start的方法中,将SimpleServer类初始化完毕,再调用其start方法即可实现服务器的启动工作,简洁而又直观,这也是大部分JEE服务器的实现方式。

注意 构造函数简化,再简化,应该达到“一眼洞穿”的境界。

[改善Java代码]构造函数尽量简化相关推荐

  1. java 代码解析工具_改善 Java 代码质量的工具与方法

    原标题:改善 Java 代码质量的工具与方法 我们可能见过上面的有关代码质量的图片,究竟如何衡量一段代码好坏? 代码质量是什么?为什么它很重要? 作家通过他的著作来讲述了一个清晰的.令人信服的故事.他 ...

  2. 改善Java代码有哪些方法?

    前言 Java是一门优秀的面向对象的编程语言,针对遇到同样的一个问题会有很多中解法哪种实现方法是最好的呢,还需要不断的探究JDK的底层原理.我会例出Java改善的建议哦,希望大家可以在平时开发工作去使 ...

  3. [改善Java代码]适时选择不同的线程池来实现

    Java的线程池实现从最根本上来说只有两个:ThreadPoolExecutor类和ScheduledThreadPoolExecutor类,这两个类还是父子关系,但是Java为了简化并行计算,还提供 ...

  4. [改善Java代码]养成良好习惯,显式声明UID

    建议11: 养成良好习惯,显式声明UID 我们编写一个实现了Serializable接口(序列化标志接口)的类, Eclipse马上就会给一个黄色警告:需要增加一个Serial Version ID. ...

  5. [改善Java代码]使用valueOf前必须进行校验

    每个枚举都是java.lang.Enum的子类,都可以访问Enum类提供的方法,比如hashCode(),name(),valueOf()等..... 其中valueOf()方法会把一个String类 ...

  6. java 不可修改的集合对象_[改善Java代码]asList方法产生的List对象不可更改

    上一个建议之处了asList方法在转换基本类型数组时候存在的问题,在看下asList方法返回的列表有何特殊的地方.看代码: importjava.util.Arrays;importjava.util ...

  7. [改善Java代码]减少HashMap中元素的数量

    在系统开发中我们经常会使用HashMap作为数据集容器,或者是用缓冲池来处理,一般很稳定,但偶尔也会出现内存溢出的问题(OutOfMemory错误),而且这经常是与HashMap有关的.而且这经常是与 ...

  8. [改善Java代码]让工具类不可实例化

    建议42: 让工具类不可实例化 Java项目中使用的工具类非常多,比如JDK自己的工具类java.lang.Math.java.util.Collections等都是我们经常用到的.工具类的方法和属性 ...

  9. [改善Java代码]非稳定排序推荐使用List

    我们知道Set与List的最大区别就是Set中的元素不可以重复(这个重复指的equals方法的返回值相等),其他方面则没有太大的区别了,在Set的实现类中有一个比较常用的类需要了解一下:TreeSet ...

最新文章

  1. UEFI引导的系统下装双系统解决方案
  2. 【面向工业界】京东NLP落地应用实战
  3. html图片标签和语义化标签和音频
  4. 【背包】小明逛超市(jzoj 2148)
  5. 416B. Art Union
  6. linux的基础知识——本地套接字
  7. mysql启动失败2005_数据库2005服务启动不了
  8. yum,yum指向,yum源创建
  9. 大数据:知识,真正的价值体现
  10. 0.96OLED显示原理及FPGA驱动程序
  11. 移动端页面SEO优化需要注意的10个要点
  12. ps cs6安装教程
  13. OpenMV新手上路1 -- OpenMV简介、参数描述
  14. 第二集:你真的会吸气吗 ?科学呼吸法(汇播课程演说笔记)
  15. 细说group by 和having 以及count函数的 联合使用
  16. 【5. Redis的高并发高可用】
  17. DFT的一些基本性质
  18. React高阶组件探究
  19. 子墨对酒《三国杀》里论模式(一)工厂模式
  20. AAC文件格式与解码流程(未完待续)

热门文章

  1. PCA原理分析和Matlab实现方法(三)
  2. 分布式实时计算—实时计算相关问题及解决方案
  3. 华为上机考试题系列(二):HJ107求解立方根
  4. 安装使用Frida在Android上进行hook
  5. 更换checkbox的原有样式
  6. hbase shell-dml(数据管理指令)
  7. 关于手思3.0 代码规范
  8. 【Linux】Linux 目录结构
  9. [JDK]找不到或无法加载主类 java
  10. 实验十:程序结构与数组 8、数组实训