Java中的代码块
1 局部代码块
局部代码块定义在方法中,用花括号’{}'包含。例如在method()方法中我们创建一个局部代码块。
public class Test01 {
public void methodA(){
{
int aa = 15;
System.out.println("aa = " + aa);
System.out.println("我是局部代码块");
}
}
public static void main(String[] args) {
Test01 test01 = new Test01();
test01.methodA();
}
}
aa = 15
我是局部代码块
Process finished with exit code 0
在上述代码中,我们可以直接去掉代码块的花括号,运行效果和加代码块一致。那么,有什么必要使用局部代码块吗?局部代码块可以限制变量的生命周期,也就是说在代码块中创建的变量只在代码块中有效,当代码块运行结束,变量就会被释放,从而节省内存空间。具体看一下以下代码来理解局部代码块的释放变量内存空间。
首先在局部代码块之外定义一个int类型的aa变量。然后在局部代码块中再次定义一个int类型的aa变量,此时报错说是[重复定义了两个变量aa。如果我们将上述方法中的局部变量和局部代码块交换一下顺序会怎么样呢?
可以看到,这样就不会报错了,这是因为在代码块中使用完变量之后就会释放掉,所以出了代码块,内存中就不再存在age这个变量了。
2 构造代码块
public class Test03 {
public Test03() {
System.out.println("无参构造");
}
public Test03(int num) {
System.out.println("带参构造");
}
{
System.out.println("构造代码块");
}
public static void main(String[] args) {
Test03 test = new Test03();
System.out.println("-------------");
Test03 test2 = new Test03(1);
}
}
构造代码块
无参构造
-------------
构造代码块
带参构造
可以看出:无论是使用无参构造还是有参构造来创建对象,首先都会执行构造代码块中的内容。所以它可以对对象进行初始化;即每个对象都具有的功能可以放在构造代码块中,在对象创建时,就会实现该功能,从而减少代码的冗余度,提高代码复用性。
3 静态代码块
静态代码块同样是定义在类中的,相对于构造代码块,只是在花括号前加了一个static修饰符。同样的,通过代码来看一下它的作用。
public class Test04 {
public Test04() {
System.out.println("无参构造");
}
public Test04(int num) {
System.out.println("带参构造");
}
static {
System.out.println("静态代码块");
}
public static void main(String[] args) {
Test04 st = new Test04();
System.out.println("----------------");
Test04 st2 = new Test04(1);
}
}
静态代码块
无参构造
----------------
带参构造
Process finished with exit code 0
可以看到,我们以无参和带参的形式创建对象,虽然同构造代码块一样,执行在构造方法前面,但是静态代码块仅执行一次。
静态代码块是在类加载时初始化的,随着类的加载而加载;所以有些代码必须在项目启动的时候就执行的话,需要使用静态代码块。
4 优先级顺序
因为局部代码块是需要调用包含局部代码块的方法才能得到执行,所以可以比较main()方法、静态代码块、构造代码块、构造方法之间的执行顺序。
public class Test05 {
public Test05() {
System.out.println("无参构造");
}
public Test05(int x) {
System.out.println("带参构造");
}
{
System.out.println("构造代码块");
}
static {
System.out.println("静态代码块");
}
void method() {
{
System.out.println("局部代码块");
}
}
public static void main(String[] args) {
System.out.println("main()方法");
Test05 yxJ = new Test05(); // 无参方式创建对象
yxJ.method();
System.out.println("---------------------------------------");
Test05 yxji = new Test05(1); // 带参方式创建对象
yxji.method();
}
}
静态代码块
main()方法
构造代码块
无参构造
局部代码块
---------------------------------------
构造代码块
带参构造
局部代码块
Process finished with exit code 0
所以可以看出来优先执行顺序是静态代码块 > main()方法 > 构造代码块 > 构造方法。
5 继承关系的优先级
再看一下具有继承关系的子类和父类之间的静态代码块、构造代码块、构造方法之间的执行顺序。
class Father {
public Father() {
System.out.println("父类无参构造");
}
Father(int num) {
System.out.println("父类带参构造");
}
{
System.out.println("父类构造代码块");
}
static {
System.out.println("父类静态代码块");
}
}
class Son extends Father {
public Son() {
System.out.println("子类无参构造");
}
public Son(int num) {
System.out.println("子类带参构造");
}
{
System.out.println("子类构造代码块");
}
static {
System.out.println("子类静态代码块");
}
}
public class Init {
public static void main(String[] args) {
Son son = new Son();
Son son2 = new Son(1);
System.out.println("-------------------------");
Father father = new Father();
Father father2 = new Father(1);
System.out.println("-------------------------");
Father father3 = new Son();
Father father4 = new Son(1);
}
}
父类静态代码块
子类静态代码块
父类构造代码块
父类无参构造
子类构造代码块
子类无参构造
父类构造代码块
父类无参构造
子类构造代码块
子类带参构造
-------------------------
父类构造代码块
父类无参构造
父类构造代码块
父类带参构造
-------------------------
父类构造代码块
父类无参构造
子类构造代码块
子类无参构造
父类构造代码块
父类无参构造
子类构造代码块
子类带参构造
Process finished with exit code 0
所以优先级是父类静态代码块 > 子类静态代码块 > 父类构造代码块 > 父类构造方法 > 子类构造代码块 > 子类构造方法。