静态代码块与非静态代码块

1.下面这段代码的输出结果是什么?

public class HelloB extends HelloA {
    public HelloB() {
        System.out.println("HelloB");
    }

    {
        System.out.println("I’m B class");
    }
    static {
        
        System.out.println("static B");
    }

    public static void main(String[] args) {
        new HelloB();
    }
}

class HelloA {
    public HelloA() {
        System.out.println("HelloA");
    }

    {
        System.out.println("I’m A class");
    }
    static {
        System.out.println("static A");
    }
}

static A
static B
I’m A class
HelloA
I’m B class
HelloB()

解析:

  • 存在父子关系,又有静态代码块,先执行父类静态代码块,再执行子类静态代码块,故打印static A static B
  • 存在父子关系,又有非静态代码块,先执行父类非静态代码块,父类构造器,再执行子类非静态代码块,子类构造器故打印I’m A class HelloA I’m B class HelloB

静态代码块=>非静态代码块=>构造方法
父子关系:父类静态代码块=>子类静态代码块=>父类非静态代码块=>父类构造函数=>子类非静态代码块=>子类构造函数

非静态代码块

{ 
   System.out.println("I'm B class");
}

这个是非静态代码块,也叫普通代码块,在每个类创建前(构造函数之前)调用 ,不创建对象的时候,不被调用,代码块中定义的变量都是局部变量,如果有父子关系的话,先执行父类的,再执行子类的。非静态代码块属于对象,静态代码块属于类。

  • 例1:
package com.mousycoder.staticTest;

public class Child extends Father{
    
    static {
        System.out.println("child-->static");
    }
    
    private int n = 20;
    
    {
        System.out.println("Child Non-Static");
        n = 30;
    }
    
    public int x = 200;
    
    public Child() {
        this("The other constructor");
        System.out.println("child constructor body: " + n);
    }
    
    public Child(String s) {
        System.out.println(s);
    }
    
    public void age() {
        System.out.println("age=" + n);
    }
    
    public void printX() {
        System.out.println("x=" + x);
    }
    
    public static void main(String[] args) {
        new Child().printX();
    }
}

class Father {
    
    static {
        //System.out.println("n+"+n);
            //当n定义在下面时,会提示Cannot reference a field before it is defined,
            //所以必须把n定义移到上面才可以输出
        System.out.println("super-->static");
    }
    
    public static int n = 10;
    public int x = 100;
    
    public Father() {
        System.out.println("super's x=" + x);
        age();
    }
    
    {
        System.out.println("Father Non-Static");
    }
    
    public void age(){
        System.out.println("nothing");
    }
}

结果:

super-->static
child-->static
Father Non-Static
super's x=100
age=0
Child Non-Static
The other constructor
child constructor body: 30
x=200

解析:

  • 先执行静态代码块,有父子关系,先执行父类静态代码块,打印super–>static
  • 执行子类静态代码块,打印child–>static
  • 实例化子类的时候,先实例化父类,在调用父类构造方法之前,先调用父类非静态代码块,打印Father Non-Static
  • 实例化父类,调用父类构造方法,执行第一句 System.out.println(“super’s x=” + x); 在调用构造方法之前,成员变量x 已经被赋值为100,打印super’s x=100
  • 执行age()方法,因为main方法中真正实例化的是子类,子类又重写了父类的age方法,所以执行子类的age方法,此时子类还没初始化,默认n=0 ,打印age=0
  • 实例化子类,调用子类构方法之前,调用子类非静态代码块,打印Child Non-Static
  • 调用子类构造方法,执行this(“The other constructor”),调用子类的Child(String s),打印The other constructor
  • 执行System.out.println("child constructor body: " + n); 初始化之前 成员变量初始值为20,执行完非静态代码块后 n被修改成30 ,所以这里n =30 打印child constructor body: 30
  • 执行printX()方法,打印x = 200

注意点:

子类重写父类的方法
虽然非静态代码块里是局部变量,但是可以改变类的成员变量的值
  • 例2
public class Father {

    {
        System.out.println("Father___非静态代码块");
    }

    public Father() {
        System.out.println("Father___构造方法");
    }
}

class Son extends Father {

    {
        System.out.println("Son___非静态代码块");
    }

    public Son() {
        System.out.println("Son___构造方法");
    }
}

class Test {

    public static void main(String [] args){
        Father son=new Son();
               son=new Son();
    }
}

输出结果:

Father___非静态代码块
Father___构造方法
Son___非静态代码块
Son___构造方法
  • 加载顺序
    非静态代码块 > 构造方法
  • 原因
    因为是继承关系,所以首先会加载Father的非静态代码块,然后加载Son的非静态代码块,之后在加载Father的构造方法,然后在加载Son的构造方法,且非静态代码块每实例化一次就会执行一次。

静态代码块

static {
  System.out.println("static B");
}

属于静态代码块,使用场景:
1.想用一个存储区域来保存一个特定的数据,不想创建对象
2.创建一个特殊的方法,与这个类的对象没有关联,即使没创建对象,也可以调用

  • 例1:
public class Father {

   static{
       System.out.println("Father___静态代码块");
   }

   public Father() {
       System.out.println("Father___构造方法");
   }

}

class Son extends Father {

   static{
       System.out.println("Son___静态代码块");
   }

   public Son() {
       System.out.println("Son___构造方法");
   }

}

class Test {

   public static void main(String [] args){

       Father son=new Son();
              son=new Son();

   }
}

运行结果:

Father___静态代码块
Son___静态代码块
Father___构造方法
Son___构造方法
  • 加载顺序:

    静态代码块 > 构造器。

  • 原因:

    因为是继承关系,所以首先会加载Father的静态代码块,然后加载Son的静态代码块,之后在加载Father的构造方法,然后在加载Son的构造方法,且静态代码块在这个类被调用时只执行一次。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值