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

来源:互联网 发布:labp网络管理协议 编辑:程序博客网 时间:2024/04/29 11:02

静态域、非静态域、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 declaredStatic final declaredStatic blockInitalizeaed AbstractAbstract ConstractorUsual declaredFinal declaredConstructor-------------------------------MethodStatic MethodFinal MethodStatic final MethodAbstract methodTest covered method-------------------------------Static MethodException 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 declaredStatic final declaredStatic block-------------------------------Initalizeaed AbstractAbstract ConstractorUsual declaredFinal declaredConstructor-------------------------------MethodTest 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 declaredStatic final declaredStatic block-------------------------------Initalizeaed AbstractAbstract ConstractorUsual declaredFinal declaredConstructor-------------------------------MethodTest 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详解

0 0
原创粉丝点击