zoukankan      html  css  js  c++  java
  • java 单例模式

    java单例模式

    今天和同事在项目中用了一下单例模式,闲下来了解了一下单例模式的实现方式。参考了 http://cantellow.iteye.com/blog/838473 这篇博客。了解到主要有懒汉模式和饿汉模式两种。前者实现了我们所知道的lazy load。
    在这里我选了两种实现方式自己实现了一下。
    

    饿汉

    public class Singleton {
        public static String NAME = "Singleton";
        private static Singleton singleton = new Singleton();
    
        private Singleton() {
            System.out.println("initial Singleton");
        }
    
        public static Singleton getSingleton() {
            return singleton;
        }
    }
    

    懒汉

    public class InnerSingleton {
    
        public static String NAME = "InnerSingleton";
    
        private static class Singleton {
            private static final InnerSingleton INNER_SINGLETON = new InnerSingleton();
        }
    
        private InnerSingleton() {
            System.out.println("initial InnerSingleton");
        }
    
        public static InnerSingleton getSingleton() {
            return Singleton.INNER_SINGLETON;
        }
    }
    

    思考

    看了类加载和类初始化的一些相关知识,参考 https://www.cnblogs.com/zhguang/p/3154584.html
    
    不管使用什么样的类加载器,类都是在第一次被用到时,动态加载到JVM的。这句话有两层含义:
    Java程序在运行时并不一定被完整加载,只有当发现该类还没有加载时,才去本地或远程查找类的.class文件并验证和加载;
    

    当程序创建了第一个对类的静态成员的引用(如类的静态变量、静态方法、构造方法——构造方法也是静态的)时,才会加载该类。Java的这个特性叫做:动态加载。
    需要区分加载和初始化的区别,加载了一个类的.class文件,不以为着该Class对象被初始化,事实上,一个类的初始化包括3个步骤:

    加载(Loading),由类加载器执行,查找字节码,并创建一个Class对象(只是创建);
    链接(Linking),验证字节码,为静态域分配存储空间(只是分配,并不初始化该存储空间),解析该类创建所需要的对其它类的应用;
    初始化(Initialization),首先执行静态初始化块static{},初始化静态变量,执行静态方法(如构造方法)。
    

    类初始化的时机分以下几种情况

    使用new关键字实例化对象的时候
    读取或设置一个类的静态字段(被final修饰,已在编译期把结果放入常量池的静态字段除外, 举个例子?)
    调用一个类的静态方法
    使用java.lang.reflect包的方法对类进行反射调用的时候
    当初始化一个类的时候,如果发现其父类还没有进行初始化,需要先初始化其父类
    虚拟机启动时要执行的主类(包含main()方法的类)

    当我把类加载和初始化分开来看时,我发现不论是饿汉模式还是懒汉模式都是在调用getInstance方法时,才会将构造器里的话打印出来,这样看是否都是懒汉模式呢?现在看起来实例都是在类初始化的时候创建的。留有疑问。
    

    更新 解答疑问

    public static void main(String[] args) {
            String a = Singleton.NAME;
            String b = InnerSingleton.NAME;   
        }
    

    可以使用这种方法触发类的装载,在这里类的装载=加载+初始化。使用上述方法的结果如下图所示:

    而如果只装载类,利用classloader,两种方法是都不会打印出来的。可是如果利用classforname方法,是和上述截图的结果一致的。这是因为,classforname除了会将类加载还会对static变量进行初始化,参考 https://blog.csdn.net/qq_27093465/article/details/52262340

  • 相关阅读:
    columns布局应用场景
    flex速记
    css属性选择器模糊匹配
    ydui的rem适配方案
    vscode搜索失效问题
    ESP8266 超声波测距模块HC-SR04
    树莓派PICO Wifi 无线网卡 esp82666接线图
    查看数据库容量大小
    面试官问我JVM内存结构,我真的是
    深入浅出Java内存模型
  • 原文地址:https://www.cnblogs.com/gaofengfengfeng/p/9111650.html
Copyright © 2011-2022 走看看