一、局部代码块:
局部代码块定义在方法中,用花括号'{}'包含。例如在method()方法中我们创建一个局部代码块。
void method() { { int x = 22; System.out.println("age = " + x); System.out.println("这是一个局部代码块"); } }
在上述代码中,我们可以直接去掉代码块的花括号,运行效果和加代码块一致。那么,有什么必要使用局部代码块吗?
局部代码块可以限制变量的生命周期,也就是说在代码块中创建的变量只在代码块中有效,当代码块运行结束,变量就会被释放,从而节省内存空间。
具体看一下以下代码来理解局部代码块的释放变量内存空间。
void method() { int age = 10; { int age = 100; //此处报错[Duplicate local variable age];去掉前面的int类型声明即可 } System.out.println("age = " + age); }
首先在局部代码块之外定义一个int类型的age变量。然后在局部代码块中再次定义一个int类型的age变量,此时报错说是[重复定义了两个变量age]。如果我们将上述方法中的局部变量和局部代码块交换一下顺序会怎么样呢?
void method() { { int age = 100; } int age = 10; System.out.println("age = " + age); }
可以看到,这样就不会报错了,这是因为在代码块中使用完变量之后就会释放掉,所以出了代码块,内存中就不再存在age这个变量了。
二、构造代码块:
构造代码块是定义在类中方法外的,同样是用花括号'{}'包含;例如:
public class Test { public Test() { System.out.println("无参构造"); } public Test(int num) { System.out.println("带参构造"); } { System.out.println("构造代码块"); } public static void main(String[] args) { Test test = new Test(); System.out.println("-------------"); Test test2 = new Test(1); } }
之前的代码块叫做局部代码块是因为它放在方法中,相当于是局部位置。那么此处的构造代码块是否和构造方法有着千丝万缕的联系呢?
通过上述代码,我们可以验证一下,运行结果如下:
[构造代码块 无参构造 ------------- 构造代码块 带参构造]
可以看出:无论是使用无参构造还是有参构造来创建对象,首先都会执行构造代码块中的内容。所以它可以对对象进行初始化;即每个对象都具有的功能可以放在构造代码块中,在对象创建时,就会实现该功能,从而减少代码的冗余度,提高代码复用性。
3. 静态代码块:
静态代码块同样是定义在类中的,相对于构造代码块,只是在花括号前加了一个static修饰符。同样的,我们通过代码来看一下它的作用。
public class StaticTest { public StaticTest() { System.out.println("无参构造"); } public StaticTest(int num) { System.out.println("带参构造"); } static { System.out.println("静态代码块"); } public static void main(String[] args) { StaticTest st = new StaticTest(); System.out.println("----------------"); StaticTest st2 = new StaticTest(1); } }
运行结果为:
[静态代码块 无参构造 ---------------- 带参构造]
可以看到,我们以无参和带参的形式创建对象,虽然同构造代码块一样,执行在构造方法前面,但是静态代码块仅执行一次。
静态代码块是在类加载时初始化的,随着类的加载而加载;所以有些代码必须在项目启动的时候就执行的话,需要使用静态代码块。
4. 优先级顺序:
因为局部代码块是需要调用包含局部代码块的方法才能得到执行,所以可以比较main()方法、静态代码块、构造代码块、构造方法之间的执行顺序。
public class YouXianJi { public YouXianJi() { System.out.println("无参构造"); } public YouXianJi(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()方法"); YouXianJi yxJ = new YouXianJi(); // 无参方式创建对象 yxJ.method(); System.out.println("---------------------------------------"); YouXianJi yxji = new YouXianJi(1); // 带参方式创建对象 yxji.method(); } }
运行结果为:
[静态代码块 main()方法 构造代码块 无参构造 局部代码块 --------------------------------------- 构造代码块 带参构造 局部代码块]
所以可以看出来优先执行顺序是静态代码块 > main()方法 > 构造代码块 > 构造方法。
然后我们再看一下具有继承关系的子类和父类之间的静态代码块、构造代码块、构造方法之间的执行顺序。
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); } }
运行结果如下:
[父类静态代码块 子类静态代码块 父类构造代码块 父类无参构造 子类构造代码块 子类无参构造 父类构造代码块 父类无参构造 子类构造代码块 子类带参构造 ------------------------- 父类构造代码块 父类无参构造 父类构造代码块 父类带参构造 ------------------------- 父类构造代码块 父类无参构造 子类构造代码块 子类无参构造 父类构造代码块 父类无参构造 子类构造代码块 子类带参构造]
所以优先级是父类静态代码块 > 子类静态代码块 > 父类构造代码块 > 父类构造方法 > 子类构造代码块 > 子类构造方法。
那么如果把Son类改成
public class Son extends Father{ public Son() { System.out.println("子类无参构造"); } public Son(int num) { System.out.println("子类带参构造"); } { System.out.println("子类构造代码块"); } static { System.out.println("子类静态代码块"); } public static void main(String[] args) { System.out.println("---------begin-----------"); Son son = new Son(); } }
执行son类的结果是什么?
结果:
父类静态代码块 子类静态代码块 ---------begin----------- 父类构造代码块 父类无参构造 子类构造代码块 子类无参构造
还没有评论,来说两句吧...