zoukankan      html  css  js  c++  java
  • Java构造时成员初始化的陷阱

    让我们先来看两个类:Base和Derived类。注意其中的whenAmISet成员变量,和方法preProcess()。

    情景1:(子类无构造方法)

    class Base {
        Base() {
            preProcess();
        }
    
        void preProcess() {
        }
    }
    
    class Derived extends Base {
        public String whenAmISet = "set when declared";
    
        void preProcess() {
            whenAmISet = "set in preProcess()";
        }
    }
    
    public class StaticTest {
        public static void main(String[] args) {
            Derived d = new Derived();
            System.out.println(d.whenAmISet);
        }
    }

    当.java源代码转换成一个.class文件后,其转换成类似下面的等价代码:

    class Base {
        Base() {
            preProcess();
        }
    
        void preProcess() {
        }
    }
    
    class Derived extends Base {
        public String whenAmISet;
    
        {whenAmISet = "set when declared";}
    
        void preProcess() {
            whenAmISet = "set in preProcess()";
        }
    }
    
    public class StaticTest {
        public static void main(String[] args) {
            Derived d = new Derived();
            System.out.println(d.whenAmISet);
        }
    }

    输出结果是: set when declared

    情景2:(子类添加了构造方法)

    class Base {
        Base() {
            preProcess();
        }
    
        void preProcess() {
        }
    }
    
    class Derived extends Base {
        public String whenAmISet = "set when declared";
    
        public Derived() {
            whenAmISet = "set in constructor";
        }
    
        void preProcess() {
            whenAmISet = "set in preProcess()";
        }
    }
    
    public class StaticTest {
        public static void main(String[] args) {
            Derived d = new Derived();
            System.out.println(d.whenAmISet);
        }
    }

    当.java源代码转换成一个.class文件后,其转换成类似下面的等价代码:

    class Base {
        Base() {
            preProcess();
        }
    
        void preProcess() {
        }
    }
    
    class Derived extends Base {
        public String whenAmISet;
    
        public Derived() {
            whenAmISet = "set when declared";
            whenAmISet = "set in constructor";
        }
    
        void preProcess() {
            whenAmISet = "set in preProcess()";
        }
    }
    
    public class StaticTest {
        public static void main(String[] args) {
            Derived d = new Derived();
            System.out.println(d.whenAmISet);
        }
    }

    输出结果为:set in constructor

    情景3:(赋值的细节)

    public class Singleton {
    
        private static Singleton mInstance = new Singleton();  // 位置1
        public static int counter1;
        public static int counter2 = 0;
    
        private Singleton() {
            counter1++;
            counter2++;
        }
    
        public static Singleton getInstantce() {
            return mInstance;
        }
    
        public static void main(String[] args) {
            Singleton singleton = Singleton.getInstantce();
            System.out.println("counter1: " + singleton.counter1);
            System.out.println("counter2: " + singleton.counter2);
        }
    }

    当.java源代码转换成一个.class文件后,其转换成类似下面的等价代码:

    public class Singleton {
    
        private static Singleton mInstance;
        public static int counter1;
        public static int counter2;
    
        static {
            mInstance = new Singleton();
            counter2 = 0;
        }
    
        private Singleton() {
            counter1++;
            counter2++;
        }
    
        public static Singleton getInstantce() {
            return mInstance;
        }
    
        public static void main(String[] args) {
            Singleton singleton = Singleton.getInstantce();
            System.out.println("counter1: " + singleton.counter1);
            System.out.println("counter2: " + singleton.counter2);
        }
    }
    • 在Prepare阶段,mInstance、counter1、counter2的初始值为(null,0,0);
    • 执行至 mInstance = new Singleton()时,进行实例创建并调用构造方法,使counter1、counter2变量的值改变为(1,1);
    • 执行counter2 = 0时,counter2的值再次置为0,最终程序的输出结果为:counter1: 1   counter2: 0

    同理,以下代码的最终输出结果为:counter1: 1  counter2: 1

    public class Singleton {
    
        public static int counter1;
        public static int counter2 = 0;
        private static Singleton mInstance = new Singleton(); // 位置2
    
        private Singleton() {
            counter1++;
            counter2++;
        }
    
        public static Singleton getInstantce() {
            return mInstance;
        }
    
        public static void main(String[] args) {
    
            Singleton singleton = Singleton.getInstantce();
            System.out.println("counter1: " + singleton.counter1);
            System.out.println("counter2: " + singleton.counter2);
        }
    }

    原因分析:

    1. 陈皓博客
    2. Java Tutor - Visualize Java code execution to learn Java online (also visualize PythonJavaJavaScriptTypeScriptRubyC, and C++ code)
  • 相关阅读:
    js的继承实现方式
    jdbc调用通用存储过程完成分页
    最近在忙些什么......
    【转】说服下属的“攻心术”
    设计模式原则详解
    【转】职场学做“功夫熊猫”
    内核初始化优化宏 ,初始化顺序, __init,__devexit等
    Linux 嵌入式启动以及优化
    每个程序员都该知道的10大编程格言
    linux 用户空间 和 内核空间 延时函数
  • 原文地址:https://www.cnblogs.com/echo1937/p/6243271.html
Copyright © 2011-2022 走看看