你是否多次被问到类似下面的程序的执行顺序?
public class Main {
public static void main(String[] args) {
A test = new B();
}
}
class A {
{
System.out.println("A构造代码块");
}
static {
System.out.println("A静态代码块");
}
public A() {
System.out.println("A构造函数代码块");
}
}
class B extends A{
{
System.out.println("B构造代码块");
}
static {
System.out.println("B静态代码块");
}
public B() {
System.out.println("B构造函数代码块");
}
}
根据类的加载顺序,父类先于子类加载,故A的构造函数比B的构造函数调用要快,故输出一定有下面的相对输出顺序:
... //省略代表也许有内容
A构造函数代码块
...
B构造函数代码块
...
那其他的呢?它们何时被执行的?
这时你也许和我一样当时缺少认识一个知识点: 代码块!!!
代码块
代码块,顾名思义是一整块代码的意思,它由{}+里面的逻辑代码组成,完成一定的任务。代码块不能独立执行,必须有运行的主体,比如一个函数不能独立执行,必须被调用。
{
... //代码块
}
普通代码块
我们用得最多,就是方法名大括号里的代码段,在方法名调用时被执行
void f(){
... //普通代码块
}
同步代码块
有关键词修饰的代码块synchronized,但要注意一点,它不是可以修饰任意的代码块的,如
class B extends A{
synchronized{ //代码块1
System.out.println("B构造代码块");
}
public synchronized void f() { //代码块2
}
...
}
eclipse上会提示代码块红色错误,而代码块2没有,至于原因我还不清楚,有清楚的跟我说哈!
静态代码块
静态代码就是被static修饰的代码块, 在类被加载时便执行
static{
... //静态代码块
}
还有static想反不能修饰方法里面的代码块,无论是否为静态方法,如
public static void f() {
static {
}
}
eclipse上也会提示代码块红色错误,,至于原因我也还不清楚,有清楚的跟我说哈!
构造代码块和构造函数代码块
为什么我们将它们两个放在一起,因为构造代码块的执行主体是构造函数,也就是构造函数被调用但其代码块还没被执行时会先去执行构造代码块,所以构造代码块会在构造函数代码块之前执行,如下面代码
class A {
{
System.out.println("A构造代码块");
}
...
public A() {
System.out.println("A构造函数代码块");
}
}
当构造函数A()被调用时,会先去执行构造代码块,我们此时也许可以把A()看成C语言的include,而构造代码块是它引入的内容。
小结
一个java文件从被加载到被卸载这个生命过程,总共要经历5个阶段,JVM将类加载过程分为: >>
加载->链接(验证+准备+解析)->初始化(使用前的准备)->使用->卸载
当 执行 A a = new A()时,代码块的执行顺序为
静态代码块>构造代码块>构造函数代码块
回看题目
当 执行A test = new B()时,A类被加载,B类也被加载,故会先后执行A、B类静态代码块;A类先初始化,故先后执行A类构造代码块、构造函数代码块;最后在执行B类的构造代码块和构造函数代码块。实验结果为
A静态代码块
B静态代码块
A构造代码块
A构造函数代码块
B构造代码块
B构造函数代码块
public class Main {
public static void main(String[] args) {
A test = new B();
}
}
class A {
{
System.out.println("A构造代码块");
}
static {
System.out.println("A静态代码块");
}
public A() {
System.out.println("A构造函数代码块");
}
}
class B extends A{
{
System.out.println("B构造代码块");
}
static {
System.out.println("B静态代码块");
}
public B() {
System.out.println("B构造函数代码块");
}
}
延伸
我们在来看看向类添加变量和静态变量初始化后的结果
......
class B extends A{
D d = new D();
{
System.out.println("B构造代码块");
}
static {
System.out.println("B静态代码块");
}
static C c = new C();
public B() {
System.out.println("B构造函数代码块");
}
}
class C{
C(){
System.out.println("C");
}
}
class D{
D(){
System.out.println("D");
}
}
当 执行 A a = new A()时,代码块的执行顺序为
静态代码块、静态变量>构造代码块、变量>构造函数代码块
静态代码块和静态变量 、构造代码块和变量的初始化顺序取决于他们的在代码中的顺序,就如加减乘除。