问:Java 代码块是什么?代码块的分类有哪些?作用是什么?
答:所谓代码块就是用大括号 {} 将多行代码封装在一起形成一个独立的数据体,用于实现特定的需求,一般来说代码块是不能单独运行的,它必须要有运行主体。
普通代码块(局部代码快)是在方法名后面用 {} 括起来的代码段,不能够单独存在,必须要紧跟在方法名后面且必须使用方法名调用它,作用是限定变量的生命周期和提高效率。
构造代码块是在类中方法外用 {} 括起来的代码,作用是把所有构造方法中相同的内容抽取出来,将来在调用构造方法的时候会去自动调用构造代码块,构造代码快优先于构造方法。
静态代码块是在类中方法外用 {} 括起来且添加了 static 前缀修饰的代码,作用是随着类的加载而加载且只加载一次。
同步代码块是方法中使用 synchronized 关键字修饰并使用 {} 括起来的代码片段,表示同一时间只能有一个线程进入到该代码块中,作用是一种多线程并发保护机制。
问:Java 中静态代码块、构造代码块、构造方法的执行顺序是什么?
答:因为静态代码块作用于类级别,构造代码块和构造方法作用于对象级别,所以静态代码块是随着类的加载而被执行,只要类被加载了就会执行,而且只会加载一次,主要用于给类进行初始化;构造代码块在每次创建一个对象时就会执行一次且优先于构造函数,主要用于初始化不同对象共性的初始化内容和初始化实例环境;构造方法在每次创建一个对象时就会执行一次,同时构造方法是给特定对象进行初始化,而构造代码是给所有对象进行初始化;所以通过分析得出他们三者的执行顺序为 静态代码块 > 构造代码块 > 构造方法。
问:下面代码第一次运行的结果是什么?
class BaseTmp { BaseTmp() { System.out.println("BaseTmp instance."); } } class Base { BaseTmp tmp = new BaseTmp(); static { System.out.println("Base static{}."); } Base() { System.out.println("Base instance."); } } class BaseChild extends Base { BaseTmp tmp = new BaseTmp(); static { System.out.println("BaseChild static{}."); } BaseChild() { System.out.println("BaseChild instance."); } } public class Demo { public static void main(String argv[]) { new BaseChild(); } }
答:如上代码段的运行结果如下。
Base static{}. BaseChild static{}. BaseTmp instance. Base instance. BaseTmp instance. BaseChild instance.
首先程序加载了 Demo 类进来,接着执行 Demo 类中程序的入口 main 方法,在 main 方法中我们创建了 BaseChild 实例,而第一次创建 BaseChild 实例前需要先把 BaseChild 类加载进来,而 BaseChild 又继承自 Base 类,所以要加载 BaseChild 得先加载 Base 类,在加载 Base 类时由于 Base 类中有一个静态代码块,所以会先执行打印 Base static{}.,接着加载了 BaseChild 类执行了其中的静态代码块打印为 BaseChild static{}.,当类加载完成以后就开始实例化阶段了,实例化 BaseChild 对象之前得先实例化 Base 对象(因为子类构造方法会调用父类构造方法,所以得先实例化父类),实例化 Base 对象前还得先初始化(即获取类的属性并初始化),所以 Base 类中 BaseTmp 属性先被实例化,所以打印 BaseTmp instance.,接着执行 Base 类的构造方法打印 Base instance.,然后回退到子类也是先初始化然后实例化,同理打印 BaseTmp instance. 和 BaseChild instance.。