zoukankan      html  css  js  c++  java
  • Java类初始化顺序经典实例

    一、阿里巴巴笔试题:

    复制代码
     1 public class T  implements Cloneable {
     2     public static int k = 0;
     3     public static T t1 = new T("t1");
     4     public static T t2 = new T("t2");
     5     public static int i = print("i");
     6     public static int n = 99;
     7 
     8     public int j = print("j");
     9     
    10     {
    11         print("构造块");
    12     }
    13 
    14     static {
    15         print("静态块");
    16     }
    17 
    18     public T(String str) {
    19         System.out.println((++k) + ":" + str + "    i=" + i + "  n=" + n);
    20         ++n;
    21         ++i;
    22     }
    23 
    24     public static int print(String str) {
    25         System.out.println((++k) + ":" + str + "   i=" + i + "   n=" + n);
    26         ++n;
    27         return ++i;
    28     }
    29     
    30     public static void main(String[] args) {
    31         
    32     }
    33 }
    复制代码

    二、加载过程分析:

    执行main时,先加载所在类,声明静态变量,并初始化静态变量执行静态代码块(按顺序执行)

    初始化到t1时,暂停类加载,先实例化,此时k=0,而i,n都未初始化,系统默认值为0
    初始化j时,k自增为1,i,n为0,输出“1:j i=0 n=0”,n,i自增为1
    执行代码块,输出“2:构造块 i=1 n=1”,n,i自增为2
    执行构造函数,输出“3:t1 i=2 n=2”,n,i自增为3

    初始化到t2时,暂停类加载,先实例化,此时k=3,i,n都还未初始化,但已自增为3
    初始化j时,k自增为4,i,n未初始化为3,输出“4:j i=3 n=3”,n,i自增为4
    执行代码块,输出“5:构造块 i=4 n=4”,n,i自增为5
    执行构造函数,输出“6:t2 i=5 n=5”,n,i自增为6

    初始化i,输出“7:i i=6 n=6”,n,i自增为7,返回自增后的i赋值给i
    初始化n,赋值99
    执行静态块,输出“8:静态块 i=7 n=99”,i自增为8,n自增为100

    完成类加载

    三、涉及知识点:
    1.类加载过程:
    加载某类前先加载其父类
    加载某类时,先声明静态成员变量,初始化为默认值,再初始化静态成员变量执行静态代码块
    初始化静态成员变量执行静态代码块时,是按顺序执行(初始化静态成员变量的本质就是静态代码块)

    2.实例化过程:
    对某类实例化前,先对其父类进行实例化
    实例化某类时,先声明成员变量,初始化为默认值,再初始化成员变量执行代码块
    初始化成员变量执行代码块时,是按顺序执行

    3.在某类加载过程中调用了本类实例化过程(如new了本类对象),则会暂停类加载过程先执行实例化过程,执行完毕再回到类加载过程


    4.类的主动使用与被动使用:
    主动使用例子:
    1):最为常用的new一个类的实例对象
    2):直接调用类的静态方法。
    3):操作该类或接口中声明的非编译期常量静态字段
    4):反射调用一个类的方法。
    5):初始化一个类的子类的时候,父类也相当于被程序主动调用了
    (如果调用子类的静态变量是从父类继承过来并没有复写的,那么也就相当于只用到了父类的东东,和子类无关,
    所以这个时候子类不需要进行类初始化)。
    6):直接运行一个main函数入口的类。

    所有的JVM实现,在首次主动使用某类的时候才会加载该类。

    被动使用例子:
    7):子类调用父类的静态变量,子类不会被初始化。只有父类被初始化。对于静态字段,只有直接定义这个字段的类才会被初始化.
    8):通过数组定义来引用类,不会触发类的初始化,如SubClass[] sca = new SubClass[10];
    9):访问类的编译期常量,不会初始化类

    5.编译期常量:
    写到类常量池中的类型是有限的:String和几个基本类型
    String值为null时,也不会写到类常量池中
    使用new String("xx")创建字符串时,得到的字符串不是类常量池中的

    6.对于通过new产生一个字符串(假设为 ”china” )时,会先去常量池中查找是否已经有了 ”china” 对象,
    如果没有则在常量池中创建一个此字符串对象,然后堆中再创建一个常量池中此 ”china” 对象的拷贝对象。

    7.类成员变量才会有默认的初始值
    byte:0(8位)
    short:0(16位)
    int:0(32位)
    long:0L(64位)
    char:u0000(16位),代表NULL
    float:0.0F(32位)
    double:0.0(64位)
    boolean: flase

    8.局部变量声明以后,Java 虚拟机不会自动的为它初始化为默认值。
    因此对于局部变量,必须先经过显示的初始化,才能使用它。
    如果编译器确认一个局部变量在使用之前可能没有被初始化,编译器将报错。

    9.数组和String字符串都不是基本数据类型,它们被当作类来处理,是引用数据类型。
    引用数据类型的默认初始值都是null

  • 相关阅读:
    Notes of Daily Scrum Meeting(12.18)
    Notes of Daily Scrum Meeting(12.17)
    Notes of Daily Scrum Meeting(12.16)
    Notes of Daily Scrum Meeting(12.8)
    Notes of Daily Scrum Meeting(12.5)
    Notes of Daily Scrum Meeting(12.3)
    Notes of Daily Scrum Meeting(11.12)
    Linux中profile、bashrc、bash_profile之间的区别和联系
    Linux GCC编译
    mysql 5.7.16 远程连接
  • 原文地址:https://www.cnblogs.com/CodingAndRiding/p/7599805.html
Copyright © 2011-2022 走看看