• 今天你的静态变量和静态代码块执行了吗?


    摘要:今天你的静态变量和静态代码块执行了吗?

    本文分享自华为云社区《【java】静态变量和静态代码块那些事》,作者: 大金(内蒙的)。

    今日题目:

    今天你的静态变量和静态代码块执行了吗?

    话不多说,开始今天的题目讲解吧。

    先介绍个常识:

    静态成员属性的初始化早于静态代码块;
    静态代码块是指的类的初始化操作,初始化早于对象的创建;
    类静态域的只会初始化一次。

    题目一:输出啥?

    class Father{
        public static int m = 33;
        static{
            System.out.println("父类被初始化");
        }
    }
    
    class Child extends Father{
        static{
            System.out.println("子类被初始化");
        }
    }
    
    class StaticTest{
        public static void main(String[] args){
            System.out.println(Child.m);
            System.out.println(new Child());
       }
    }

    答案:
    父类被初始化
    33
    子类被初始化
    Child1@2781e022

    题目二:输出啥?

    class Const{  
        public static final String NAME = "我是常量";  
        static{  
            System.out.println("初始化Const类");  
        }  
    }  
    
    public class FinalTest{  
        public static void main(String[] args){  
            System.out.println(Const.NAME);  
        }  
    }  

    答案:我是常量
    详细说明:
    static final的变量是在类加载的准备阶段(还没有到初始化):
    为类的静态变量分配内存,并将其赋默认值

    对于该阶段有以下几点需要注意:

    • 只对static修饰的静态变量进行内存分配、赋默认值(如0、0L、null、false等)。
    • 对static final的静态字面值常量直接赋初值(赋初值不是赋默认值)。

    题目三:输出啥?

    class Const{  
        static{  
            System.out.println("初始化Const类");  
        }  
    }  
     
    public class ArrayTest{  
        public static void main(String[] args){  
            Const[] con = new Const[5];  
        }  
    }  

    输出:空

    题目四:输出啥?

    class Other {
        public static Other o1 = new Other();
    
        public static Other o2 = new Other();
        {
            System.out.println("构造块");
        }
        static {
            System.out.println("静态块");
        }
    
        public static void main(String[] args) {
            Other other = new Other();
        }
    }

    答案:
    构造块
    构造块
    静态块
    构造块

    脑瓜子是不是嗡嗡的!!!

    下面介绍一下,类加载过程,帮你debug下。

    类加载分为以下步骤:

    整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。

    • 加载:二进制.class文件各种文件加载一遍,类加载器去加载的
    • 验证:验证类的正确性,像是格式啊、方法重写啥的啊
    • 准备:静态域的初始化赋值,这个是给个默认值啊。
    • 解析:符号引用(编程原理)解析为直接引用。
    • 初始化:静态域的代码里面赋值。

    初始化过程,就是常识中的静态域加载的过程。

    以下四种情况触发。

    • 遇到new、getstatic、putstatic、invokestatic这四条字节码指令时,如果类还没有进行过初始化,则需要先触发其初始化。生成这四条指令最常见的Java代码场景是:使用new关键字实例化对象时、读取或设置一个类的静态字段(static)时(被static修饰又被final修饰的,已在编译期把结果放入常量池的静态字段除外)、以及调用一个类的静态方法时。
    • 使用Java.lang.refect包的方法对类进行反射调用时,如果类还没有进行过初始化,则需要先触发其初始化。
    • 当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化。
    • 当虚拟机启动时,用户需要指定一个要执行的主类,虚拟机会先执行该主类。

    除了上面四种情况,有几种特殊情况。类的初始化会被动加载。

    • 通过子类引用父类中的静态字段,这时对子类的引用为被动引用,因此不会初始化子类,只会初始化父类。
    • 常量在编译阶段会存入调用它的类的常量池中,本质上没有直接引用到定义该常量的类,因此不会触发定义常量的类的初始化。这里实际上完成了“准备”阶段。
    • 通过数组定义来引用类,不会触发类的“初始化”。

    再看一遍题目:

    所以,结合常识:
    静态成员变量的初始化早于静态代码块;
    静态代码块是指的类的初始化操作,初始化早于对象的创建;
    类静态域的只会初始化一次。
    再看一遍上面的代码,是不是能得出答案了呢?

     

    点击关注,第一时间了解华为云新鲜技术~

  • 相关阅读:
    JQuery常用的api[最好是系统地学习一下《锋利的JQuery》]
    soapui icon以及resource的理解
    《Effective C++ 》学习笔记——条款02
    android移植pppoe拨号上网的全过程
    tomcat dbcp 基于jndi当配置java.sql.SQLException: Already closed
    【iOS】文件下载小记
    Amazon S3数据一致性模型
    ARM裸编程系列---UART
    如何做程序猿SOHO它定购家庭赚外快?
    HDU 4940(杭电更多的学校#7 1006) Destroy Transportation system(到处乱混)
  • 原文地址:https://www.cnblogs.com/huaweiyun/p/15762457.html
Copyright © 2020-2023  润新知