谈到代码块,大家可能会不屑一顾,但是你真正懂它们吗?可以从下面几点检验:
- 代码块的定义及分类
- 代码块的作用
- 代码块的执行顺序
代码块的那些琐事
- 代码块的定义及共性
- 简言之,用 {} 包起来的代码片段,就可以称之为代码块;
- 不同类型的代码块之间的执行顺序与其代码的相对位置无关;
- 同一种类型的代码块在代码中由上而下顺序执行;
- 代码块的分类
- 局部代码块
定义:处于处于方法中的局部位置;
作用:限定变量、对象的生命周期,迟创建、早释放,提高内存利用率; - 构造代码块
定义:处于类中的成员位置,用{}括起来的代码片段。
说明:每创建一个对象,就会调用构造代码块一次。且在调用构造方法之前、静态方法之后调用;
作用:抽取出对象共同的初始化属性代码。 - 静态代码块
定义:与构造代码块类似,不过其用 static 来修饰;
说明:在类加载的过程中被调用,且只加载一次、最先被调用。同一个类中静态代码块会先于 main 函数执行;
作用:对类的数据进行初始化,仅只执行一次。
- 局部代码块
一个实例搞定代码块家族的调用顺序
package com.george.j2se.codeblock;
/***
* @author george
* @email qtozeng@qq.com
* @date 2016-4-3
*/
class Student {
static {
System.out.println("我是 Student 静态代码块");
}
{
System.out.println("我是 Student 构造代码块");
}
public Student() {
System.out.println("我是 Student 无参构造方法");
}
}
public class StudentTest {
static {
System.out.println("我是 main 函数所处类的静态代码块,我最先执行!");
}
public static void main(String[] args) {
System.out.println("我是 main方法");
Student s1 = new Student();
Student s2 = new Student();
}
}
执行输出:
我是 main 函数所处类的静态代码块,我最先执行!
我是 main方法
我是 Student 静态代码块
我是 Student 构造代码块
我是 Student 无参构造方法
我是 Student 构造代码块
我是 Student 无参构造方法
网友提供的一段代码
package com.george.j2se;
/***
* @author george
* @email qtozeng@qq.com
* @date 2016-4-3
*/
public class TestStaticCon {
public static int a = 0;
static {
a = 10;
System.out.println("静态代码块在执行 a=" + a);
}
{
a = 8;
System.out.println("构造代码块在执行 a=" + a);
}
public TestStaticCon() {
this("带参构造方法中被无参构造调用 a=" + a); // 调用另外一个构造方法
System.out.println("无参构造方法执行 a=" + a);
}
public TestStaticCon(String n) {
System.out.println(n);
System.out.println("带参构造方法中执行 a=" + a);
}
public static void main(String[] args) {
TestStaticCon tsc = null;
System.out.println("main 方法要创建对象了...");
tsc = new TestStaticCon();
}
}
执行输出:
静态代码块在执行 a=10
main 方法要创建对象了...
构造代码块在执行 a=8
带参构造方法中被无参构造调用 a=10
带参构造方法中执行 a=8
无参构造方法执行 a
- 问题来了:
有同学可能会疑问,为什么在带无参构造中调用带参构造方法时,a 的值为 10,不应该是 8 吗?那是因为没有理解构造代码块执行时机的本质,其是在创建对象前被调用,而不是在调用构造方法前被调用。 - 思维误区:
构造方法被调用与创建对象是不等价的。显然,一个构造方法可以调用其它构造方法,然而,在此过程中,可能就只创建了一个对象。构造方法除了会被 jvm 自动调用外,其与普通方法无根本区别,只是一般用作给对象初始化而已。、 - 那么结论:
所以更为准确的说,构造代码块是在创建对象前被调用的,也可以说,是在调用最后一个构造方法前被调用的。(若仍有疑惑可以实验以下实例) - 反观字节码:
一个补充的实例
package com.george.j2se.codeblock;
/***
* @author george
* @email qtozeng@qq.com
* @date 2016-4-3
*/
public class PersonTest {
private int id;
private String name;
{
System.out.println("构造代码块被调用了!");
}
public PersonTest() {
this(100);
System.out.println("public PersonTest() 被调用...");
}
public PersonTest(int id) {
this(id, "tom");
this.id = id;
System.out.println("public PersonTest(int id) 被调用..." );
}
public PersonTest(int id, String name) {
this.id = id;
this.name = name;
System.out.println("public PersonTest(int id, String name) 被调用...");
}
public static void main(String[] args) {
PersonTest pt = new PersonTest();
}
}
执行输出:
构造代码块被调用了!
public PersonTest(int id, String name) 被调用...
public PersonTest(int id) 被调用...
public PersonTest() 被调用...
同学不妨用断点调试一下代码,结果就一目了然了。