Java - 对象的初始化

  • Java中的初始化

    • java会尽力保证所有的变量在使用前都能够得到恰当的初始化,避免出现一堆null导致报错

      • 因此当变量是 基本类型 时,Java都会给他初始化一个初值

      • 但如果变量是 对象类型 时,因为Java无法知道这个自定义的类型要给什麽初始化的值,因此如果没有初始化的话,还是会得到一个null值

      • 初始化的顺序 : 先执行宣告变量时的初始化 -> 再执行构造器方法

      class Leaf {
          int level;
      }
      ​
      class MyTest {
          //可以在此处宣告成员变量时,就给一个初始值
          //或是也可以写在构造器裡,两种办法都可以
          int i = 100; 
          int x;
          //也可以在宣告时,直接初始化对象类型
          Leaf leaf = new Leaf(); 
          Leaf leaf2;
          
          MyTest(){
              i = 10;
              
              //输出 10,此i被初始化了两次,第一次被设为100,第二次被设为10
              System.out.println(i); 
        
              //输出 0,此x则是因为被Java初始化了一次,所以值才会是0
              System.out.println(x); 
      
              //输出Leaf@3af49f1c(hashCode)
              //因为此对象类型的变量在宣告时被初始化过了,所以有实际指到某的对像
              System.out.println(leaf); 
      
              //输出 0
              System.out.println(leaf.level);        
             
              //输出 null,因为Java不知道给这个对象设什麽初值,所以不会初始化对象类型的变量
              System.out.println(leaf2); 
      
              //抛出异常 NullPointerException
              System.out.println(leaf2.level); 
          }
      }
      ​
      public class Main {
          public static void main(String[] args) {
              MyTest myTest = new MyTest();
          }
      }
    • 静态数据的初始化

      • 静态数据static和类裡平常的成员变量一样,也是java会进行基本的初始化(基本类型给值,对象类型给null),然而因为无论创建多少对象,静态变量都只佔用一份储存数据,所以如果想在宣告静态变量之外进行初始化,需要使用静态块来初始化

        • 静态块只有在必要时刻才会进行,并不是程序启动就会运行,只有在此类第一个对象被创建、或者第一次访问静态变量时,静态块才会被运行,所有的静态变量就会被初始化,此后,所有静态对象不会再次被初始化,因为所有此类的对象中,只会有一份静态变量,而他们也只能初始化一次

        • 由下面的例子可以看到,当静态变量i被访问时,静态块就会被执行了,所有的静态变量ij都会被初始化,因此当后面又在new一个对象时,静态块并不会再次被初始化,因为整份类的所有对象中,静态变量只有一份

        • 使用static {}会创建一个静态块,而使用{}则是创建普通块,这两个方法块差别很大,很坑,要特别注意

        class MyTest {
            static int i = 10;
            static int j = 20;
        ​
            //定义一个静态块,静态变量的初始化放在这裡,或是在宣告变量时初始化
            static {
                System.out.println("静态块初始化");
                i = 100;
            }
            
            //要注意,这种前面没有加 static 关键字的区块,不是静态块
            //是每创建一次对象都会执行的普通块,并且会在构造器前执行,很坑
            {
                System.out.println("普通块初始化");
            }
            
            MyTest() {
                System.out.println("constructor");
            }
        }
        ​
        public class Main {
            public static void main(String[] args) {
                System.out.println("调用静态变量 i");
                System.out.println(MyTest.i);
        ​
                System.out.println("new对象开始");
                MyTest myTest = new MyTest();
                MyTest myTest2 = new MyTest();
                System.out.println("new对象结束");
                
                System.out.println("调用静态变量 j");
                System.out.println(MyTest.j);
            }
        }
        调用静态变量 i
        静态块执行
        100
        new对象开始
        普通块初始化
        constructor
        普通块初始化
        constructor
        new对象结束
        调用静态变量 j
        20
    • 初始化的顺序

      • 创建一个对象时,初始化的顺序

        • 静态变量宣告时初始化 -> 静态块初始化 -> 普通的变量宣告时初始化 -> 普通块初始化 -> 构造器初始化

      • 访问一个静态变量时,初始化的顺序

        • 静态变量宣告时初始化 -> 静态块初始化

  • 有继承关系时的初始化

    • 把握一个重点,就是静态块永远优先于普通块+构造器,然后才是Parent优先于Child

      • 创建一个Child对象时,初始化的顺序

        • Parent静态块 -> Child静态块 -> Parent普通块 + Parent构造器 -> Child普通块 + Child构造器

      • 访问一个静态变量时,初始化的顺序

        • 如果是访问Parnet的静态变量,那就是只初始化 Parent的静态块

        • 但如果访问了Child自己宣告的静态变量,则会初始化 Parent静态块 + Child静态块

      class Parent {
          public static int x = 10;
      ​
          static {
              System.out.println("parent 静态块");
          }
      ​
          {
              System.out.println("parent 普通块");
          }
      ​
          Parent() {
              System.out.println("parent constructor");
          }
      }
      ​
      class Child extends Parent {
          public static int y = 20;
      ​
          static {
              System.out.println("child 静态块");
          }
      ​
          {
              System.out.println("child 普通块");
          }
      ​
          Child() {
              super();
              System.out.println("child constructor");
          }
      }
      ​
      public class Main {
          public static void main1(String[] args) {
              //main1 直接new一个Child对象
              Child child = new Child();
          }
          
          public static void main2(String[] args) {
              //main2 调用Parent的静态变量
              System.out.println("parent x: " + Child.x);
          }
          
          public static void main3(String[] args) {
              //main3 调用Child的静态变量
              System.out.println("child y: " + Child.y);
          }
      }
      //main1结果 直接new一个Child对象
      parent 静态块
      child 静态块
      parent 普通块
      parent constructor
      child 普通块
      child constructor
      ​
      //main2结果 调用Parent的静态变量
      parent 静态块
      parent x: 10
          
      //main3结果 调用Child的静态变量
      parent 静态块
      child 静态块
      child y: 20

猜你喜欢

转载自blog.csdn.net/weixin_40341116/article/details/82773666