java 代码块

基本介绍

  • 代码化块又称为初始化块,属于类中的成员(即是类的一部分),类似于方法中的方法体,通过{}包围起来。
  • 但和方法不同,代码块没有方法名,没有返回,没有参数,只有方法体,而且不同通过对象或类显式调用,而是加载类时,或创建对象时隐式调用。
  • 基本语法

[修饰符] {

        // 代码 ...

};

说明:

(1)修饰符可以不写,如果要写的话只能写 static

(2)代码块分为两类:使用 static 修饰的叫静态代码块,否则就叫普通代码块/非静态代码块

(3)逻辑语句可以为任何逻辑语句(输入、输出、方法调用、循环、判断等)

(4)分号可以写上,也可以省略

代码块的好处

  • 相当于另外一种形式的构造器(对构造器的补充机制),可以做初始化的操作
  • 应用场景:如果多个构造器中都有重复的语句,可以抽取到代码块中,提高代码的重用性
public class Test {
    public static void main(String[] args) {
        /*
         * 输出:
         * 电影屏幕打开了...
         * 广告开始了...
         * 电影开始了...
         * Movie(String name) 被调用了
         * -------------------
         * 电影屏幕打开了...
         * 广告开始了...
         * 电影开始了...
         */
        Movie m1 = new Movie("前任");
        System.out.println("-------------------");
        Movie m2 = new Movie("前任2",50.9);
    }
}

class Movie {
   public String name;
   public double price;

   {
        /*
         * 把两个构造器中都有的重复代码提取出来,放在代码块中
         * 在创建对象时,会先执行代码块中的语句,再执行构造方法中的代码
         */
        System.out.println("电影屏幕打开了...");
        System.out.println("广告开始了...");
        System.out.println("电影开始了...");
   };

   public Movie(String name){
        // System.out.println("电影屏幕打开了...");
        // System.out.println("广告开始了...");
        // System.out.println("电影开始了...");

        System.out.println("Movie(String name) 被调用了");
        this.name = name;
   }

   public Movie(String name, double price){
        // System.out.println("电影屏幕打开了...");
        // System.out.println("广告开始了...");
        // System.out.println("电影开始了...");

        System.out.println("Movie(String name, double price) 被调用了");
        this.name = name;
        this.price = price;
   }
}

代码块的使用细节

  • static 代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次。如果是普通代码块,每创建一个对象,就会执行一次普通代码块
  • 类加载的时机
    • 创建对象实例时(new)
    • 创建子类的对象实例时,父类也会被加载
    • 使用类的静态成员时(静态属性、静态方法)
  • 普通代码块在创建对象实例时,会被隐式地调用。被创建一次,就会调用一次普通代码块。如果只是使用类的静态成员,普通代码块不会被执行,因为使用类的静态成员时没有创建对象
  • 创建一个对象时,在一个类中的调用顺序是:
    1. ​​​​​​调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按它们定义的顺序调用)
    2. 调用普通代码块和普通属性初始化(注意:普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按定义的顺序调用)​
    3. 调用构造方法
public class Test {
    public static void main(String[] args) {
        /**
         * 类中的调用顺序:调用静态属性初始化和静态代码块 ——> 调用普通属性初始化和普通代码块 ——> 调用构造器
         * 1、静态代码块和静态属性初始化优先级一样,按照它们的定义顺序使用
         * 2、普通代码块和普通属性初始化优先级一样,按照它们的定义顺序使用
         * 3、调用构造器
         * 输出:
         * getN1 被调用....
         * 类A 静态代码块被调用...
         * 类A 普通代码块被调用...
         * getN2 被调用....
         * A 类无参构造器被调用...
         */
        A a = new A();
    }
}

class A {
    { // 普通代码块
        System.out.println("类A 普通代码块被调用...");
    }

    private static int n1 = getN1(); // 静态属性初始化
    private int n2 = getN2(); // 普通属性初始化

    public A(){ // 构造器
        System.out.println("A 类无参构造器被调用...");
    }
    static { // 静态代码块
        System.out.println("类A 静态代码块被调用...");
    }

    public static int getN1() {
        System.out.println("getN1 被调用....");
        return 100;
    }

    public int getN2() {
        System.out.println("getN2 被调用....");
        return 200;
    }
}
  • 构造方法(构造器)的最前面其实隐含了 super() 和调用普通代码块和普通属性初始化。静态相关的代码块、属性初始化,在类加载时,就执行完毕,因此是优先于构造器和普通代码块执行的
public class Test {
    public static void main(String[] args) {
        /**
         * 构造方法(构造器)的最前面其实隐含了 super() 和调用普通代码块和普通属性初始化
         * 静态相关的代码块、属性初始化,在类加载时,就执行完毕
         * 因此是优先于构造器和普通代码块执行的
         * 输出:
         * // 调用 super() 的输出结果
         * 类AAA 普通代码块被调用...
         * AAA 类无参构造器被调用...
         * 类BBB 普通代码块被调用... //调用本类的普通代码块
         * BBB 类无参构造器被调用... // 执行 BBB 的构造器
         */
        BBB bbb = new BBB();
    }
}

class AAA { // 父类是 Object ,在 Object 的构造器中无输出,所以看不出效果
    { // 普通代码块
        System.out.println("类AAA 普通代码块被调用...");
    }

    public AAA(){ // 构造器
        /**
         * 此处隐藏了两句代码的执行
         * (1)super()
         * (2)调用本类的普通代码块和普通属性初始化
         */
        System.out.println("AAA 类无参构造器被调用...");
    }
}

class BBB extends AAA {
    { // 普通代码块
        System.out.println("类BBB 普通代码块被调用...");
    }

    public BBB(){ // 构造器
        /**
         * 此处隐藏了两句代码的执行
         * (1)super()
         * (2)调用本类的普通代码块和普通属性初始化
         */
        System.out.println("BBB 类无参构造器被调用...");
    }
}
  • 创建一个子类对象时(继承关系),它们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造器的调用顺序如下:
    1. 父类的静态代码块和静态属性初始化(两者优先级一样,按定义的顺序执行)
    2. 子类的静态代码块和静态属性初始化(两者优先级一样,按定义的顺序执行)
    3. 父类的普通代码块和普通属性初始化(两者优先级一样,按定义的顺序执行)
    4. 父类的构造方法
    5. 子类的普通代码块和普通属性初始化(两者优先级一样,按定义的顺序执行)
    6. 子类的构造方法
    7. 总结:父类的静态 —> 子类的静态 —> 父类的普通和构造 —> 子类的普通和构造
public class Test {
    public static void main(String[] args) {
        /**
         * 1、先进行类加载
         * 1.1、加载父类 A:执行静态相关代码
         * 输出:(1)getN1()...  (2)类A 的第一个静态代码块被调用...
         * 1.2、加载子类 B:执行静态相关代码
         * 输出:(3)getN3()...  (4)类B 的一个静态代码块...
         * 2、创建对象
         * 2.1、执行子类的构造方法,其中隐含 super(),所以执行父类的构造器
         * 2.2、父类的构造器也隐含 super() 和 父类普通代码块和普通属性初始化的调用,
         * 输出:(5)类A 的第一个普通代码块被调用...  (6)getN2()...
         * 2.3、然后执行父类的构造方法
         * 输出:(7)A 类无参构造器被调用...
         * 2.4、子类普通代码块和普通属性初始化的调用
         * 输出:(8)getN4()...  (9)类B 的第一个普通代码块...
         * 2.5、然后才执行子类的构造方法
         * 输出:(10)B 类无参构造器被调用...
         */
        new B();
    }
}

class A { // 父类是 Object ,在 Object 的构造器中无输出,所以看不出效果
    private static int n1 = getN1();

    static {
        System.out.println("类A 的第一个静态代码块被调用...");
    }
    { // 普通代码块
        System.out.println("类A 的第一个普通代码块被调用...");
    }

    public int n3 = getN2();

    public static int getN1() {
        System.out.println("getN1()...");
        return 10;
    }

    public  int getN2() {
        System.out.println("getN2()...");
        return 10;
    }

    public A(){ // 构造器
        /**
         * 此处隐藏了两句代码的执行
         * (1)super()
         * (2)调用本类的普通代码块
         */
        System.out.println("A 类无参构造器被调用...");
    }
}

class B extends A {
    public static int n3 = getN3();

    static {
        System.out.println("类B 的一个静态代码块...");
    }

    public int n5 = getN4();

    { // 普通代码块
        System.out.println("类B 的第一个普通代码块...");
    }

    public static int getN3(){
        System.out.println("getN3()...");
        return 10;
    }

    public int getN4(){
        System.out.println("getN4()...");
        return 10;
    }
    public B(){ // 构造器
        /**
         * 此处隐藏了两句代码的执行
         * (1)super()
         * (2)调用本类的普通代码块
         */
        System.out.println("B 类无参构造器被调用...");
    }
}
  • 静态代码块只能直接调用静态成员(静态方法和静态属性),普通代码块可以调用任意成员
class C {
    private static int n1 = 100;
    private int n2 = 200;

    private static void m1() {}
    private void m2() {}

    static {
        // 静态代码块,只能调用静态成员
        System.out.println(n1); // ok
        //System.out.println(n2); // 报错
        m1(); // ok
        //m2(); // 报错
    }

    {
        // 普通代码块,可以调用任意成员
        System.out.println(n1); // ok
        System.out.println(n2); // ok
        m1(); // ok
        m2(); // ok
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值