• 【JAVA笔记——道】Class初始化理解


    静态域、非静态域、Final、父类以及抽象类正常实例化

    设置Initalized用于初始化时对于结果进行输出

    //被实例化类,设置初始方法用于显示初始化标记
    public class Initalized {
        public Initalized(String s) {
            System.out.println(s);
        }
    }

    设置接口类用于测试类继承,设置内容如下

    interface InitalizeaedInterface {
        //接口中变量默认都是static final
        Initalized s1 = new Initalized("Initalizeaed Interface");
    
        //usual method
        public void test1();
    
        //static method
        //public void test2();
    
        //final method
        public void test3();
    
        //static final method
        //public void test4();
    }
    

    设置抽象类作为实现类父类

    package com.cunchen.practice.init;
    
    //设置被实例化类的父类
    public abstract class InitalizedAbstract {
        //父类中域中对于被实例化类进行实习化
        Initalized a = new Initalized("Initalizeaed Abstract");
        Initalized b;
        static Initalized c; 
    
        //被实例化类的父类的构造方法
        public InitalizedAbstract() {
            b = new Initalized("Abstract Constractor");
        }
    
        //父类的非静态方法
        public void test5() {
            b = new Initalized("Abstract method");
        }
    
        //父类的非静态方法,此方法在子类中被覆盖
        public void test6() {
            b = new Initalized("Abstract covered method");
        }
    
        //父类静态方法
        public static void test7() {
            c = new Initalized("Abstract static method");
        }
    }
    

    最终实现类如下

    //实例化类
    public class InitalizationTest extends InitalizedAbstract implements InitalizeaedInterface{
        //变量域中实例化
        Initalized s1 = new Initalized("Usual declared");
        //变量域中静态变量实例化
        static Initalized s2 = new Initalized("Static declared");
        //变量域中常量实例化
        final Initalized s5 = new Initalized("Final declared");
        //变量域中静态常量实例化
        static final Initalized s6 = new Initalized("Static final declared");
    
        Initalized s3;
        static Initalized s4;   
    
        //静态方法域中执行静态方法
        static {
            getReply();
        }
    
        //构造方法
        public InitalizationTest() {
            super();
            s3 = new Initalized("Constructor");
        }
    
        //普通方法
        public void test1() {
            s3 = new Initalized("Method");
        }
    
        //静态方法
        public static void test2() {
            s4 = new Initalized("Static Method");
        }
    
        //Final方法
        public final void test3() {
            s4 = new Initalized("Final Method");
        }
    
        //静态Final方法
        public static final void test4() {
            s4 = new Initalized("Static final Method");
        }
    
        //重写父类方法
        public void test6() {
            s3 = new Initalized("Test covered method");
        }
    
        //静态域执行方法
        public static void getReply() {
            s4 = new Initalized("Static block");
        }
    
        public static void main(String[] args) {
            //初始化过程
            InitalizationTest test = new InitalizationTest();
            System.out.println("-------------------------------");
    
            //方法执行过程
            test.test1();            //普通方法
            test.test2();            //静态方法
            test.test3();            //Final方法
            test.test4();            //Static Final 方法
            test.test5();            //父类方法
            test.test6();            //重写方法
            System.out.println("-------------------------------");
    
            //空对象访问
            test = null;
            test.test2();            //普通方法
            test.test1();            //静态方法
        }
    }
    

    实际运行结果如下

    Static declared
    Static final declared
    Static block
    Initalizeaed Abstract
    Abstract Constractor
    Usual declared
    Final declared
    Constructor
    -------------------------------
    Method
    Static Method
    Final Method
    Static final Method
    Abstract method
    Test covered method
    -------------------------------
    Static Method
    Exception in thread "main" java.lang.NullPointerException
        at com.cunchen.practice.init.InitalizationTest.main(InitalizationTest.java:74)
    
    

    得出结论如下:
    1.类内部初始化顺序为 静态域->非静态域->构造方法
    2.类实例化过程中不会对于实现的接口的域进行初始化
    3.类实例化过程中会在其构造方法之前父类初始化
    4.无论是静态方法还是非静态方法,在实例化过程中不直接执行
    5.子类重写父类方法之后调用重写方法将不会对父类方法调用
    6.静态域静态方法会在类加载时就直接进行初始化
    7.空对象可以访问静态化区域,但不可以访问非静态化区域,,这个问题还引出对象在JVM存储结构的问题,不同对象在虚拟机中不同的存储策略决定了其不同的实现方式

    反射方式

    新建RunTest类

        public class RunTest {
    
        public static void main(String[] args) throws ClassNotFoundException {          
            //反射看class初始化情况
            Class.forName("com.cunchen.practice.init.InitalizationTest");
    
            System.out.println("-------------------------------");
            InitalizationTest test = new InitalizationTest();
            System.out.println("-------------------------------");
            test.test1();
            test.test6();
            System.out.println("-------------------------------");
    
    
        }
    
    }

    执行之后得到结果如下

    Static declared
    Static final declared
    Static block
    -------------------------------
    Initalizeaed Abstract
    Abstract Constractor
    Usual declared
    Final declared
    Constructor
    -------------------------------
    Method
    Test covered method
    -------------------------------
    

    得出结论:

    1. 反射仅会目标类静态域进行初始化,而对非静态域不初始化
    2. 静态域只会在类初次加载初始化,再次加载不进行初始化
    3. 反射之后,类并未真正实例化,并未调用其构造方法

    ClassLoader加载类

    修改main方法如下:

    public static void main(String[] args) throws ClassNotFoundException {  
            ClassLoader.getSystemClassLoader().loadClass("com.cunchen.practice.init.InitalizationTest");
            System.out.println("-------------------------------");
    
            //反射看class初始化情况
            Class.forName("com.cunchen.practice.init.InitalizationTest");
    
            System.out.println("-------------------------------");
            InitalizationTest test = new InitalizationTest();
            System.out.println("-------------------------------");
            test.test1();
            test.test6();
            System.out.println("-------------------------------");
        }

    结果如下

    -------------------------------
    Static declared
    Static final declared
    Static block
    -------------------------------
    Initalizeaed Abstract
    Abstract Constractor
    Usual declared
    Final declared
    Constructor
    -------------------------------
    Method
    Test covered method
    -------------------------------

    得到结论:ClassLoader在进行类加载之后并不对类进行任何初始化操作

    深入理解

    Class的装载包括3个步骤:加载(loading),连接(link),初始化(initialize)
    Class.forName重载了两种实现方法,

         public static Class<?> forName(String className)
                    throws ClassNotFoundException
    
        public static Class<?> forName(String name, boolean initialize,
                                       ClassLoader loader)
                                       throws ClassNotFoundException

    第二个方法中的initialize方法其实就是指定Class被loading后是不是必须被初始化
    实际上第一个方法执行结果等同于Class.forName(className, true, currentLoader)

    ClassLoader.loadClass(String name)源码如下

        public Class<?> loadClass(String name) throws ClassNotFoundException {
            return loadClass(name, false);
        }
        protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException
        {
            synchronized (getClassLoadingLock(name)) {
                // First, check if the class has already been loaded
                Class<?> c = findLoadedClass(name);
                if (c == null) {
                    long t0 = System.nanoTime();
                    try {
                        if (parent != null) {
                            c = parent.loadClass(name, false);
                        } else {
                            c = findBootstrapClassOrNull(name);
                        }
                    } catch (ClassNotFoundException e) {
                        // ClassNotFoundException thrown if class not found
                        // from the non-null parent class loader
                    }
    
                    if (c == null) {
                        // If still not found, then invoke findClass in order
                        // to find the class.
                        long t1 = System.nanoTime();
                        c = findClass(name);
    
                        // this is the defining class loader; record the stats
                        sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                        sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                        sun.misc.PerfCounter.getFindClasses().increment();
                    }
                }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }

    实际执行情况为loadClass(name, false),装载的class将不会被link。

    这两个方法都用于装载Class。但如果程序依赖于Class是否被初始化,就必须用Class.forName(name)了。相信到此大家也能明白在JDBC中经常用到的加载JDBC驱动程序是什么原理了把。

    深入了解推荐
    对象生命周期详解
    Java ClassLoader详解

  • 相关阅读:
    【java】定时任务@Scheduled
    20180513 实参 形参 数组
    20180513 实参 形参
    20180513 数组 实参 形参
    <转载>二维数组回形遍历
    20180318 代码错题(8)
    20180318 代码错题(7)
    20180318 代码错题(6)
    20180318 代码错题(5)
    20180318 bit置0
  • 原文地址:https://www.cnblogs.com/cunchen/p/9464179.html
Copyright © 2020-2023  润新知