• 陈秋冬:评估AI项目 我们需要思考三个问题 2019-05-03
  • 浙江:大学生就业实习平台启用 2019-05-03
  • 人民日报人民时评:个人信息,利用好更需保护好 2019-04-21
  • 山西临汾:壶口瀑布奔腾咆哮奇景 2019-04-21
  • 蔡徐坤粉丝破千万送福利 帅气运动装长腿吸睛 2019-04-17
  • 刘爽:走进世界舞台中央的中国新角色 2019-04-15
  • 西部网(陕西新闻网)www.cnwest.com 2019-04-15
  • 为太原人才新政点赞! 2019-04-07
  • 把每一元善款都用到实处 2019-04-07
  • 当你还在担心这些问题的时候,有个人的“自由发展”吗? 2019-03-31
  • 不光人美还是真才女!欧阳娜娜9月入学伯克利音乐学院? 2019-02-27
  • 让山里娃感受智慧科技乐趣 2019-02-27
  • 文脉颂中华——黄河新闻网 2019-01-20
  • 当前位置:上海天天彩4开奖结果 >  域名 >  正文 > 胸径18公分苦楝树哪里有卖的?

    上海天天彩4开奖结果 www.rl-f1.com   交易 任务 SEO服务 站长团购 联盟

    叶扬坐在看台上看着这一幕,脸上露出了尴尬的笑容。这罗林也太强横了,竟然会以这种方式将博滕一文打败,简直是比自己还要粗暴。

    哪里有腊梅小苗供应商?

    “走吧,我们今天要去一个地方?!绷躔┳笫忠桓鲇沂忠桓?,在无数人眼红的目光下离开了小精灵中心。
    孙艺维摇了摇头,其余的人看到叶扬这幅神秘兮兮的表情,也都是围了上来。

    说完,冯瑶伸手放出自己的桃花xiao魂网,带着粉腻腻的幽香,迎风便涨,一下子便罩住了两头修罗魔神,将这两头修罗魔神裹在了一处,大网上的粉红色的淫气侵入到两头魔神身体之中,顿时将两头魔神的元阳精气抽取了精光,只剩下两具干尸掉落下去!

    JVM学习五:JVM之类加载器之编译常量和主动使用


    在学习了前面几节的内容后,相信大家已经对JAVA 虚拟机 加载类的过程有了一个认识和了解,那么本节,我们就继续进一步巩固前面所学知识和特殊点。

    一、类的初始化回顾

    类在初始化的时候,静态变量的声明语句以及静态代码块都被看作类的初始化语句,Java虚拟机会按照初始化语句在类文件中的先后顺序来依次加载它们。

    上图中a的初始化其实经过了四步
    1、a被初始化为默认值0
    2、a被赋予正确的初始值1
    3、执行静态代码块,将a的值赋为2
    4、执行静态代码块,将a的值赋为4
    因此最终的执行结果是4,一个类只能被一个ClassLoader加载一次,只有没有被加载过的类或者已经被卸载的类才可能被再次加载。类的初始化步骤如下:
    1、假如这个类还没有被加载和连接,那就先进行加载和连接
    2、假如存在直接的父类,并且这个父类还没有被初始化则先初始化直接的父类
    3、假如类中存在初始化语句,那就依次执行初始化语句。
    注意:Java虚 拟机在初始化一个类的时候要求它的父类已经被初始化,但是这条规则并不适应于接口!在初始化一个类的时候并不会初始化他所实现的接口!在初始化一个接口的 时候也不会去初始化他的父接口!因此一个父接口并不会因为他的实现类或者子接口的初始化而初始化,只有当程序使用该接口特定的静态变量的时候才会去初始化 这个接口!

    我们上面的例子印证了第三点,对于前两点我们知道我们构造一个类的时候假设它有父类,就会默认调用父类的无参构造方法,然后就初始化了父类,而初始化之前必须进行加载和连接!
    我们来看一个具体的程序来验证上面的结论,代码如下:

    class Parent{
    
        static int a=1;
    
        static{
    
           System.out.println("Parent"s static block");
    
        }
    
    }
    
    
    class Child extends Parent{
    
        static int b=2;
    
        static{
    
           System.out.println("Child"s static block");
    
        }
    
    }
    
    
    public class InitTestCase {
    
        static{
    
           System.out.println("InitTestCase"s static block");
    
        }
    
        public static void main(String[] args) {
    
           System.out.println(Child.b);
    
        }
    
    }

    这个程序很简单,我们一猜就能知道结果,因为是InitTestCase启动类,因此优先初始化!然后调用子类Child的b静态变量,Child继承自Parent,因此先初始化父类Parent,所以运行结果是:

    修改代码如下:

    class Parent{
    
        static int a=1;
    
        static{
    
           System.out.println("Parent"s static block");
    
        }
    
    }
    
    
    class Child extends Parent{
    
        static int b=2;
    
        static{
    
           System.out.println("Child"s static block");
    
        }
    }
    
    
    
    public class InitTestCase {
    
        static{
    
           System.out.println("InitTestCase"s static block");
    
        }
    
        public static void main(String[] args) {
    
           Parent parent;
    
           System.out.println("===== split line =====");
    
           parent=new Child();
    
           System.out.println(Parent.a);
    
           System.out.println(Child.b);
    
        }
    
    }

    为了能够看清楚parent具体的初始化状态,我们加入split line来隔开程序段,这样又会返回怎样的结果呢?
    刚开始的Parent是否会初始化?
    我们之前已经说的很清楚了,只有主动使用的6种情况会导致类的初始化,因此刚开始parent不会初始化,因为InitTestCase是启动类,所以最先初始化,然后是分隔符,然后初始化子类Child,初始化Child的时候发现继承了Parent,所以先初始化Parent,然后初始化Child,然后再次调用parent的静态变量,因为Parent已经初始化了,一个类只能被一个ClassLoader初始化一次,所以不会初始化Parent,直接输出Parent.a的数据,Child同理,因此最终执行结果是:

    ?

    这里也再次强调类初始化的实际为:

    只有一下6种主动使用的情况会导致类的初始化,其他任何情况都被视为是被动使用,不会导致类的初始化!
    1、创建类的实例
    2、访问某个类或接口的静态变量,或者对该静态变量赋值
    3、调用类的静态方法
    4、反射(如Class.forName(“com.yhj.jvm.classloader.finalTest.TestCase”))
    5、初始化一个类的子类
    6、Java虚拟机启动时被标明为启动类的类(Java Test)
    除了以上6种情况都属于被动使用,不会导致类的初始化。

    再来看一段代码:

    class StaticClassTest{
    
        public static int staticValue = 2 / 1;
    
        static{
    
           System.out.println("StaticClassTest"s static block!");
    
        }
    
    }
    
    
    public class TestCase {
    
        public static void main(String[] args) {
    
           System.out.println(StaticClassTest.staticValue);
    
        }
    
    }

    很显然属于调用类的静态成员变量,类会被初始化,初始化就会执行执行静态初始化语句块,就会执行System.out.println("StaticClassTest"s static block!");语句,因此运行结果如下:

    但是如果这个类的静态成员是常量呢?
    如下代码:

    class StaticClassTest{
    
        public static int staticValue = 2 / 1;
    
        static{
    
           System.out.println("StaticClassTest"s static block!");
    
        }
    
    }
    
    //===================================================================
    
    
    
    class StaticFinalTest1{
    
        public final static int staticValue = 2 / 1;
    
        static{
    
           System.out.println("StaticFinalTest1"s static block!");
    
        }
    
    }
    
    //===================================================================
    
    
    
    class StaticFinalTest2{
    
        public final static int staticValue = new Random().nextInt(10);
    
        static{
    
           System.out.println("StaticFinalTest2"s static block!");
    
        }
    
    }
    
    //===================================================================
    
    
    public class TestCase {
    
        public static void main(String[] args) {
    
           System.out.println(StaticClassTest.staticValue);
    
           System.out.println(StaticFinalTest1.staticValue);
    
           System.out.println(StaticFinalTest2.staticValue);
    
        }
    
    }

    第一个我们已经知道了,会执行静态代码块,那第二个和第三个呢?他们的区别是第二个是在第一个的基础之上将staticValue变为了final,第三个对于第二个的区别是第三个static不是一个计算的具体值,而是0-10之间的一个随机数!又有什么样的区别呢?我们先来看一下运行结果!

    ?

    二、编译时常量

    看了上面的结果,应该很好奇,为什么没有输出:StaticFinalTest1"s static block!

    StaticFinalTest1的静态代码块没有执行,即StaticFinalTest1类并没有被初始化,而StaticFinalTest2被初始化了!

    这是为什么呢?我们再来看一下他们的区别:StaticFinalTest1的静态常量值是2/1=2,对于这种值在编译的时候JVM就会把结果计算出来放进class文件中,相当于StaticFinalTest1=2,而StaticFinalTest2在编译的时候并不知道具体的数值是多少,需要运行的时候才会被赋值,所以我们可以看出,调用编译时的静态常量并不会初始化这个类(即不属于主动使用),而调用运行时的静态常量是会初始化该类的!

    我们再来改动一下上面父子类的程序

    class Parent{
    
        static int a=1;
    
        static{
    
           System.out.println("Parent"s static block");
    
        }
    
    }
    
    
    
    class Child extends Parent{
    
        static int b=2;
    
        static{
    
           System.out.println("Child"s static block");
    
        }
    
    }
    
    
    
    public class InitTestCase {
    
     
    
        public static void main(String[] args) {
    
           System.out.println(Child.a);
    
        }
    
    }

    这样执行结果有什么呢?我们直接调用子类中父类定义的a会怎样呢?
    按照我们之前的理论,执行结果应该是调用子类,先初始化父类,我们看下执行结果:

    我们看到子类好像没有被初始化,不对,是确实没有被初始化!所以我们一定要注意:JVM规范规定只有当程序访问的静态变量或静态方法确实在当前类或当前接口中定义时,才可以认为是对类或接口的主动使用,所以我们直接调用Child中没有定义的a不属于对Child的主动使用,因此没有初始化Child!

    三、ClassLoader

    调用ClassLoader类的loadClass方法加载一个类,并不是对类的主动使用,不会导致类的初始化。

    我们来看一下loadClass的API文档:

    根据二进制名称来加载类,返回该类的Class对象的实例!那什么是二进制名称?

    二进制名称我们可以理解为类的全称,如上图中的类、内部类、匿名内部类等!以前我们写的类都是通过启动类或者Web容器帮我们加载的,这里我们可以看到ClassLoader可以直接加载载这个类,但是我们看到这个类ClassLoader是抽象类。

    也就是说我们无法通过new的方法创建实例,那我们该怎么做呢?
    我们知道如果这个类不能实例化,我们可以通过他的静态方法访问这个类,我们来看一下ClassLoader的一个静态方法getSysytemClassLoader()这个方法

    ?

    看一段程序:

    class Test{
    
        static{
    
           System.out.println("Test"s static block");
    
        }
    
    }
    
    
    
    public class ClassLoaderTestCase {
    
     
    
        public static void main(String[] args) throws ClassNotFoundException {
    
           ClassLoader classLoader=ClassLoader.getSystemClassLoader();
    
           System.out.println("ClassLoader:"+classLoader);
    
           Class<?> testClass=classLoader.loadClass("com.yhj.jvm.classloader.finalTest.Test");
    
           System.out.println("using class.forName("com.yhj.jvm.classloader.finalTest.Test")");
    
           testClass=Class.forName("com.yhj.jvm.classloader.finalTest.Test");
    
        }
    
    }

    这段程序执行下来,我们来看下运行结果

    ?

    很显然,这段程序当调用loadClass的时候没有对类Test进行初始化,而当调用Class.forName的时候才被初始化,因此调用ClassLoader类的loadClass方法加载一个类,并不是对类的主动使用,不会导致类的初始化!只有主动使用的6种情况才会初始化该类!

    从加载到连接到初始化,我们看到loadClass只做加载和连接的操作,只有主动使用的6种才会对类进行初始化!

    ?

    参考资料:

    圣思园张龙老师深入Java虚拟机系列

    当前文章://www.rl-f1.com/news/2018121990638/index.html

    发布时间:2019-05-26 00:04:52

    米径4公分红叶碧桃什么价格能买到? 鸡爪槭基地提供的一份鸡爪槭小苗价格 每周一更新,海棠价格涨跌这里才是市场最前沿 棣棠常绿吗? 河北白玉兰价格便宜吗? 辽宁有种植木槿的基地吗? 米径5公分栾树什么价格能买到? 凌霄花在北方能过冬吗?

    苗圃实拍瓜子黄杨照片-全网首发 湖南可以种植红叶碧桃吗? 知母种子什么时候播种最好? 墨西哥玉米草种子哪里有卖的? 格?;ǖ氖谐〖鄹袷嵌嗌?? 秋季能不能播种早熟禾? 2月可以播种乌桕吗? 油桐树结种子吗? 紫苏种子批发去哪里?

    编辑:秉邓

      文章推荐

      分类排行榜

      专栏文章

      更多>

      服务推荐

      上海天天彩4开奖结果
      丰花蔷薇品种有哪些? 扫一扫关注最新创业资讯
    • 陈秋冬:评估AI项目 我们需要思考三个问题 2019-05-03
    • 浙江:大学生就业实习平台启用 2019-05-03
    • 人民日报人民时评:个人信息,利用好更需保护好 2019-04-21
    • 山西临汾:壶口瀑布奔腾咆哮奇景 2019-04-21
    • 蔡徐坤粉丝破千万送福利 帅气运动装长腿吸睛 2019-04-17
    • 刘爽:走进世界舞台中央的中国新角色 2019-04-15
    • 西部网(陕西新闻网)www.cnwest.com 2019-04-15
    • 为太原人才新政点赞! 2019-04-07
    • 把每一元善款都用到实处 2019-04-07
    • 当你还在担心这些问题的时候,有个人的“自由发展”吗? 2019-03-31
    • 不光人美还是真才女!欧阳娜娜9月入学伯克利音乐学院? 2019-02-27
    • 让山里娃感受智慧科技乐趣 2019-02-27
    • 文脉颂中华——黄河新闻网 2019-01-20