真的认识【static】关键字吗?

只知道static修饰的变量可以作为全局变量用,在项目里为了用着方便,将static修饰的变量加了一个volatile关键字修饰,这样多线程的时候,都可以保证自己拿到的值是主存里的最新值。先说static吧:

直接上代码

package com.demo.javase.staticdemo;

/**   
 * @ClassName:     OuterClass.java   
 * @Description:   块、静态块、构造器等执行顺序   
 * @author         KeepGoingPawn  
 * @Date           2018年8月23日 上午10:37:18  
 */
public class OuterClass
{
    /*静态代码块*/
    static{System.out.println("OuterClass static load."); }
    /*无参构造器*/
    public OuterClass(){ System.out.println("flag"); }
    /*有参构造器*/
    public OuterClass(String flag){ System.out.println("flag:"+flag); }
    /*内部类*/
    class InnerClass{private OuterClass out = new OuterClass("inner");}
    /*静态内部类*/
    static class InnerStaticClass
    {
        /*内部类的静态代码块*/
        static{System.out.println("InnerStaticClass static load.");} 
        /*外围类的静态变量*/
        private static OuterClass out = new OuterClass("innerStatic");
        /*内部类的静态方法*/
        private static void load(){System.out.println("InnerStaticClass func load().");}
    }
    /*外围静态方法*/
    public static  OuterClass getInstatnce(){return OuterClass.InnerStaticClass.out;}
    /*main函数*/
    public static void main(String[] args)
    {
        OuterClass.InnerStaticClass.load();
        OuterClass out = OuterClass.InnerStaticClass.out;
        OuterClass.InnerClass innerClass = out.new InnerClass() ;
    }
}

大家可以先猜一下,究竟会输出什么东东?
直接给答案吧,让我们循着答案去一步步解释。

OuterClass static load.
InnerStaticClass static load.
flag:innerStatic
InnerStaticClass func load().
flag:inner

上一张代码图:
这里写图片描述
由结果追溯过程:
外围类的静态块在类加载时首先执行->故出现第一行:OuterClass static load.
然后是加载静态内部类:先加载静态块,出现第二行:InnerStaticClass static load.
然后初始化静态内部类的成员变量innerStatic,调用外围类构造器,出现第三行flag:innerStatic
然后调用静态内部类的静态方法load(),出现第四行InnerStaticClass func load().
最后调用内部类的构造器生成一个内部类的对象,出现第五行flag:inner。
感觉真心有点乱,按照debug的顺序先记住。可以参考周志明大大的《深入理解JVM》第七章虚拟机类加载机制,来看这些东西,应该还好些。

PS:由static引发的一些列东西:

【1】单例模式实现:因为类只会加载一次,所以在用单例的时候,可以考虑使用静态内部类实现。
【2】静态代码块,也是在类加载的时候会发生,之前记得用java做游戏的时候,一些资源可以放到块语句中,达到预加载目的。
【3】父子类加载顺序:静态代码块、代码块、构造器、方法。加载顺序依次为:

 1. 这是父类的静态代码块!
 2. 这是子类的静态代码块! 
 3. 这是父类的局部代码块!
 4. 这是父类的构造方法!
 5. 这是子类的局部代码块!
 6. 这是子类的构造方法! 
 7. 这是子类的普通方法!
 插入代码及图片:
public class StaticDemo {
    public static void main(String[] args) {
        Student s = new Student();
        s.sayHello();}
}

class Person {
    static{System.out.println("这是父类的静态代码块!");}
          {System.out.println("这是父类的局部代码块!");}
    Person(){System.out.println("这是父类的构造方法!");}
}

class Student extends Person{
    static{System.out.println("这是子类的静态代码块!");}
          {System.out.println("这是子类的局部代码块!");}
    Student(){System.out.println("这是子类的构造方法!");    }
    public void sayHello(){System.out.println("这是子类的普通方法!");}
}

这里写图片描述
Debug时:发现如下执行顺序:
1:执行父类静态代码块
2:执行子类静态代码块
3:调用子类构造器去初始化子类,调用过程中先去调用父类构造器,调用父类构造器过程中,发现父类有代码块,所以先执行父类代码块,然后执行父类构造器
4:执行子类构造器时,发现有代码块,先去执行子类代码块,然后执行子类构造器
5:调用子类普通方法。

个人一些想法:

1.之前对父子类构造器 代码块 静态代码块等就是迷迷糊糊,通过这几个例子有了稍微清晰点的认知。
2.平时写代码注意不到这块,只有当参与一些设计时才会想到这些东东。
3.继续查漏补缺。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值