在编程过程中我们可能会遇到如下这种形式的程序:

public class Test {
{
////
}
}

这种形式的程序段我们将其称之为代码块,所谓代码块就是用大括号({})将多行代码封装在一起,形成一个独立的数据体,用于实现特定的算法。一般来说代码块是不能单独运行的,它必须要有运行主体。在Java中代码块主要分为四种:

一、 普通代码块

普通代码块是我们用得最多的也是最普遍的,它就是在方法名后面用{}括起来的代码段。普通代码块是不能够单独存在的,它必须要紧跟在方法名后面。同时也必须要使用方法名调用它。

public class Test {
public void test(){
System.out.println("普通代码块");
}
}

二 、 静态代码块

想到静态我们就会想到static,静态代码块就是用static修饰的用{}括起来的代码段,它的主要目的就是对静态属性进行初始化。

public class Test {
static{
System.out.println("静态代码块");
}
}

三、 同步代码块

使用 synchronized 关键字修饰,并使用“{}”括起来的代码片段,它表示同一时间只能有一个线程进入到该方法块中,是一种多线程保护机制。

四、 构造代码块

在类中直接定义没有任何修饰符、前缀、后缀的代码块即为构造代码块。我们明白一个类必须至少有一个构造函数,构造函数在生成对象时被调用。构造代码块和构造函数一样同样是在生成一个对象时被调用,那么构造代码在什么时候被调用?如何调用的呢?看如下代码:

public class Test {
/**
* 构造代码
*/
{
System.out.println("执行构造代码块...");
} /**
* 无参构造函数
*/
public Test(){
System.out.println("执行无参构造函数...");
} /**
* 有参构造函数
* @param id id
*/
public Test(String id){
System.out.println("执行有参构造函数...");
}
}

上面定义了一个非常简单的类,该类包含无参构造函数、有参构造函数以及构造代码块,同时在上面也提过代码块是没有独立运行的能力,他必须要有一个可以承载的载体,那么编译器会如何来处理构造代码块呢?编译器会将代码块按照他们的顺序(假如有多个代码块)插入到所有的构造函数的最前端,这样就能保证不管调用哪个构造函数都会执行所有的构造代码块。上面代码等同于如下形式:

public class Test {
/**
* 无参构造函数
*/
public Test(){
System.out.println("执行构造代码块...");
System.out.println("执行无参构造函数...");
} /**
* 有参构造函数
* @param id id
*/
public Test(String id){
System.out.println("执行构造代码块...");
System.out.println("执行有参构造函数...");
} } 运行结果 public static void main(String[] args) {
new Test();
System.out.println("----------------");
new Test("1");
}
------------
Output:
执行构造代码块...
执行无参构造函数...
----------------
执行构造代码块...
执行有参构造函数...

从上面的运行结果可以看出在new一个对象的时候总是先执行构造代码,再执行构造函数,但是有一点需要注意构造代码不是在构造函数之前运行的,它是依托构造函数执行的。正是由于构造代码块有这几个特性,所以它常用于如下场景:

      1、 初始化实例变量

如果一个类中存在若干个构造函数,这些构造函数都需要对实例变量进行初始化,如果我们直接在构造函数中实例化,必定会产生很多重复代码,繁琐和可读性差。这里我们可以充分利用构造代码块来实现。这是利用编译器会将构造代码块添加到每个构造函数中的特性。

2、 初始化实例环境

一个对象必须在适当的场景下才能存在,如果没有适当的场景,则就需要在创建对象时创建此场景。我们可以利用构造代码块来创建此场景,尤其是该场景的创建过程较为复杂。构造代码会在构造函数之前执行。

上面两个常用场景都充分利用构造代码块的特性,能够很好的解决在实例化对象时构造函数比较难解决的问题,利用构造代码不仅可以减少代码量,同时也是程序的可读性增强了。特别是当一个对象的创建过程比较复杂,需要实现一些复杂逻辑,这个时候如果在构造函数中实现逻辑,这是不推荐的,因为我们提倡构造函数要尽可能的简单易懂,所以我们可以使用构造代码封装这些逻辑实现部分。

五、 静态代码块、构造代码块、构造函数执行顺序

从词面上我们就可以看出他们的区别。静态代码块,静态,其作用级别为类,构造代码块、构造函数,构造,其作用级别为对象。

1、 静态代码块,它是随着类的加载而被执行,只要类被加载了就会执行,而且只会加载一次,主要用于给类进行初始化。

2、 构造代码块,每创建一个对象时就会执行一次,且优先于构造函数,主要用于初始化不同对象共性的初始化内容和初始化实例环境。

3、 构造函数,每创建一个对象时就会执行一次。同时构造函数是给特定对象进行初始化,而构造代码是给所有对象进行初始化,作用区域不同。

通过上面的分析,他们三者的执行顺序应该为:静态代码块 > 构造代码块 > 构造函数。

public class Test {
/**
* 静态代码块
*/
static{
System.out.println("执行静态代码块...");
} /**
* 构造代码块
*/
{
System.out.println("执行构造代码块...");
} /**
* 无参构造函数
*/
public Test(){
System.out.println("执行无参构造函数...");
} /**
* 有参构造函数
* @param id
*/
public Test(String id){
System.out.println("执行有参构造函数...");
} public static void main(String[] args) {
System.out.println("----------------------");
new Test();
System.out.println("----------------------");
new Test("1");
}
}
-----------
Output:
执行静态代码块...
----------------------
执行构造代码块...
执行无参构造函数...
----------------------
执行构造代码块...
执行有参构造函数...

参看文献:《编写高质量代码  改善java程序的151个建议》

java提高篇(十一)-----代码块的更多相关文章

  1. Java提高篇——静态代码块、构造代码块、构造函数以及Java类初始化顺序

    静态代码块:用staitc声明,jvm加载类时执行,仅执行一次构造代码块:类中直接用{}定义,每一次创建对象时执行.执行顺序优先级:静态块,main(),构造块,构造方法. 构造函数 public H ...

  2. java提高篇(十一)-----强制类型转换

    在java中强制类型转换分为基本数据类型和引用数据类型两种,这里我们讨论的后者,也就是引用数据类型的强制类型转换. 在Java中由于继承和向上转型,子类可以非常自然地转换成父类,但是父类转换成子类则需 ...

  3. Java提高篇(二七)-----TreeMap

    TreeMap的实现是红黑树算法的实现,所以要了解TreeMap就必须对红黑树有一定的了解,其实这篇博文的名字叫做:根据红黑树的算法来分析TreeMap的实现,但是为了与Java提高篇系列博文保持一致 ...

  4. java提高篇(十七)-----异常(二)

          承接上篇博文:java提高篇-----异常(一) 五.自定义异常 Java确实给我们提供了非常多的异常,但是异常体系是不可能预见所有的希望加以报告的错误,所以Java允许我们自定义异常来表 ...

  5. java提高篇(十)-----详解匿名内部类

    在java提高篇-----详解内部类中对匿名内部类做了一个简单的介绍,但是内部类还存在很多其他细节问题,所以就衍生出这篇博客.在这篇博客中你可以了解到匿名内部类的使用.匿名内部类要注意的事项.如何初始 ...

  6. java提高篇(八)----详解内部类

    可以将一个类的定义放在另一个类的定义内部,这就是内部类. 内部类是一个非常有用的特性但又比较难理解使用的特性(鄙人到现在都没有怎么使用过内部类,对内部类也只是略知一二). 第一次见面 内部类我们从外面 ...

  7. java提高篇(九)-----详解匿名内部类

    在java提高篇-----详解内部类中对匿名内部类做了一个简单的介绍,但是内部类还存在很多其他细节问题,所以就衍生出这篇博客.在这篇博客中你可以了解到匿名内部类的使用.匿名内部类要注意的事项.如何初始 ...

  8. Java提高篇---TreeMap

    TreeMap的实现是红黑树算法的实现,所以要了解TreeMap就必须对红黑树有一定的了解,其实这篇博文的名字叫做:根据红黑树的算法来分析TreeMap的实现,但是为了与Java提高篇系列博文保持一致 ...

  9. 【转】java提高篇(十)-----详解匿名内部类

    原文网址:http://www.cnblogs.com/chenssy/p/3390871.html 在java提高篇-----详解内部类中对匿名内部类做了一个简单的介绍,但是内部类还存在很多其他细节 ...

  10. java提高篇(十)-----详解匿名内部类 ,形参为什么要用final

    在java提高篇-----详解内部类中对匿名内部类做了一个简单的介绍,但是内部类还存在很多其他细节问题,所以就衍生出这篇博客.在这篇博客中你可以了解到匿名内部类的使用.匿名内部类要注意的事项.如何初始 ...

随机推荐

  1. nRF Toolbox 1.2 使用AKII的实现,而Becon始终不好使

    这几天调试使用nRF51822驱动mpu6050及其数据传输到android中,调试的过程遇到一些困难,apptimer不太会用,然后就參考了下ble_app_hrs的程序,结果成功搞定,demo的价 ...

  2. VSTO学习笔记(二)Excel对象模型

    原文:VSTO学习笔记(二)Excel对象模型 上一次主要学习了VSTO的发展历史及其历代版本的新特性,概述了VSTO对开发人员的帮助和效率提升.从这次开始,将从VSTO 4.0开始,逐一探讨VSTO ...

  3. adbetj657k

    http://www.zhihu.com/collection/24337307 http://www.zhihu.com/collection/24337259 http://www.zhihu.c ...

  4. 在Activity中为什么要用managedQuery()

    刚開始接触android的时候,每次用数据库都会犹豫使用哪种方式,一种是getContentResolver().query(...),还有一种是managedQuery(...),后来习惯了使用前一 ...

  5. 为什么使用 React? Edit on GitHub

    为什么使用 React? React 是一个 Facebook 和 Instagram 用来创建用户界面的 JavaScript 库.很人多认为 React 是 MVC 中的 V(视图). 我们创造 ...

  6. Android判断应用程序从后台回到前台

    MainActivity如下: package cc.testbackgroundtofront; import java.util.List; import android.app.Activity ...

  7. HDOJ 4249 A Famous Equation DP

    DP: DP[len][k][i][j] 再第len位,第一个数len位为i,第二个数len位为j,和的第len位为k 每一位能够从后面一位转移过来,能够进位也能够不进位 A Famous Equat ...

  8. SWT的CheckBoxTreeView的上级菜单与下级菜单的选中的实现

    是不是很神奇? treeViewer.addCheckStateListener(new ICheckStateListener() { @Override public void checkStat ...

  9. 一个简单的HTTP服务器(多线程)

    为了更好的了解HTTP协议, 特意谢了一个简单HTTP服务器, 代码只有400行. 因为很简单, 所以效率也不怎么高, 而且支持的特性也不多, 不过也可以运行, 性能跟Apache差不多. ===== ...

  10. Android网络服务发现(NSD)协议的使用

    Android的网络服务发现协议(NSD)能够用于在小范围的网络中发现邻近设备上的某个应用.这对于一些社交网络.多人游戏类的应用会很有帮助. Android的NSD的用法大致上分为四种操作: 1. 注 ...