ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

静态内部类何时初始化

2021-04-17 20:35:18  阅读:235  来源: 互联网

标签:初始化 静态 何时 System static DATE public 加载


静态内部类不持有外部类的引用

这个观点是众所周知的。虽然明白是因为其构造函数内没有传入外部类的引用。可是为什么静态类可以没有传入引用呢,静态内部类的加载又是什么样的过程呢?

这几天找到的答案,似乎都不能让我有一种豁然开朗的感觉。于是一次新探索开始了~

一开始,我是这样想的:

静态类和静态对象,静态变量,静态块等等一样,是在类初始化时就被加载的,所以可以不需要传入当前类的引用。
(关于非静态内部类,就不需要多说,一定需要外部类先实例化后才会加载。)

通过网上一个代码的思路,我写出了以下demo:

import java.util.Random;

public class OuterClass {
    public static long OUTER_DATE = System.currentTimeMillis();

    static {
        System.out.println("外部类静态块加载时间:" + System.currentTimeMillis());
    }

    public OuterClass() {
        timeElapsed();
        System.out.println("外部类构造函数时间:" + System.currentTimeMillis());
    }

    static class InnerStaticClass {
        public static long INNER_STATIC_DATE = System.currentTimeMillis();
    }

    class InnerClass {
        public long INNER_DATE = 0;
        public InnerClass() {
            timeElapsed();
            INNER_DATE = System.currentTimeMillis();
        }
    }

    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        System.out.println("外部类静态变量加载时间:" + outer.OUTER_DATE);
        System.out.println("非静态内部类加载时间"+outer.new InnerClass().INNER_DATE);
        System.out.println("静态内部类加载时间:"+InnerStaticClass.INNER_STATIC_DATE);
    }

    //单纯的为了耗时,来扩大时间差异
    private void timeElapsed() {
        for (int i = 0; i < 10000000; i++) {
            int a = new Random(100).nextInt(), b = new Random(100).nextInt();
            a = a + b;
        }
    }
}

假如我的推想没有错误的话,我想应该会这样的:

外部类常量加载时间 = 外部类静态块加载时间 = 静态内部类加载时间 < 外部类构造函数时间< 非静态内部类加载时间

Ok,我以为我离走到人生颠覆只差一个Run了 ! ✧(๑•̀ㅂ•́)و✧

结果却是:
image

不过,从上面我们可以分析出来结果是:

静态内部类和非静态内部类一样,都是在被调用时才会被加载

不信的同学可以自己试试copy以上的代码。随机调换 main()函数里的方法调用顺序,来验证以上的规律。

后来我这么想:

静态内部类其实和外部类的静态变量,静态方法一样,只要被调用了都会让外部类的被加载。不过当只调用外部类的静态变量,静态方法时,是不会让静态内部类的被加载

嗯哼~还是来一个demo,不过是改动了点上面的东西:

import java.util.Random;

public class StaticInner {
    public static long OUTER_DATE = System.currentTimeMillis();
    public static int a = 1;

    static {
        System.out.println("外部类静态块加载时间:" + System.currentTimeMillis());
    }

    public StaticInner() {
        InnerClass.timeElapsed();
        System.out.println("外部类构造函数事件:" + System.currentTimeMillis());
    }

    static class InnerStaticClass {
        static {
            System.out.println("内部类静态块加载时间:" + System.currentTimeMillis());
        }

        public static double INNER_DATE = System.currentTimeMillis();

    }

    static class InnerClass {
        public long INNER_DATE = 0;

        public InnerClass() {
            timeElapsed();
            INNER_DATE = System.currentTimeMillis();
        }

        public static void Hello() {
            System.out.println("Hello");
        }

        public static void main(String[] args) {
            //System.out.println("外部类常量加载时间:" + OuterClass.OUTER_DATE);
            InnerClass.Hello();
            StaticInner outer = new StaticInner();
            System.out.println("外部类静态变量加载时间:" + StaticInner.OUTER_DATE);
            System.out.println("外部类静态变量加载时间:" + outer.OUTER_DATE);
        }
        //单纯的为了耗时而已
        private static void timeElapsed() {
            for (int i = 0; i < 10000000; i++) {
                int a = new Random(100).nextInt(), b = new Random(100).nextInt();
                a = a + b;
            }
        }
    }
}

结果如下:
image

观点1:我说的没错吧~,调用外部类的静态变量,静态方法可以让外部类得到加载,不过这里静态内部类没有被加载

再看看下面的这段:

import java.util.Random;

public class OuterClass {
    public static long OUTER_DATE = System.currentTimeMillis();
    public static int a = 1;
    static {
        System.out.println("外部类静态块加载时间:" + System.currentTimeMillis());
    }

    public OuterClass() {
        timeElapsed();
        System.out.println("外部类构造函数事件:" + System.currentTimeMillis());
    }

    static class InnerStaticClass {
        static {
            System.out.println("内部类静态块加载时间:" + System.currentTimeMillis());
        }
        public static long INNER_STATIC_DATE = System.currentTimeMillis();

    }

    class InnerClass {
        public long INNER_DATE = 0;
        public InnerClass() {
            timeElapsed();
            INNER_DATE = System.currentTimeMillis();
        }
    }

    public static void Hello(){System.out.println("Hello");}

    public static void main(String[] args) {
        System.out.println("内部类静态变量加载时间:" + InnerStaticClass.INNER_STATIC_DATE );
        System.out.println("外部类静态变量加载时间:" + OuterClass.OUTER_DATE );
    }

    //单纯的为了耗时而已
    private void timeElapsed() {
        for (int i = 0; i < 10000000; i++) {
            int a = new Random(100).nextInt(), b = new Random(100).nextInt();
            a = a + b;
        }
    }
}

结果:
image

观点2:可以看出,我们其实加载静态内部类的时候,其实还会先加载外部类,才加载静态内部类

由观点1与观点2联立,以上论点得证!
好,回归主题,为什么静态内部类可以不传入引用呢?

因为其本质就是针对外部类的内部类,而不是对象的内部类,不必用this来调用。

首先,从静态的概念出发理解,静态修饰过后的一切物件都只与类相关,不与对象引用相关

As we known,静态变量,静态方法,静态块等都是类级别的属性,而不是单纯的对象属性。他们在类第一次被使用时被加载(记住,是一次使用,不一定是实例化)。我们可以简单得用 类名.变量 或者 类名.方法来调用它们。与调用没有被static 修饰过变量和方法不同的是:一般变量和方法是用当前对象的引用(即this)来调用的,静态的方法和变量则不需要。从一个角度上来说,它们是共享给所有对象的,不是一个角度私有。这点上,静态内部类也是一样的。

静态内部类的加载过程:
静态内部类的加载不需要依附外部类,在使用时才加载。不过在加载静态内部类的过程中也会加载外部类。以上花了很多功夫来说明了

标签:初始化,静态,何时,System,static,DATE,public,加载
来源: https://www.cnblogs.com/stu-jyj3621/p/14671926.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有