Java知识碎片整理(5)——static关键字与单例设计模式

static——2016/10/28
单例模式——2017/1/13

static关键字用途:

  1. 修饰静态变量
  2. 修饰静态方法,或者叫实用用法(utility method)

静态变量:

静态变量是一个类的共有性质:all objects of one class share same static fields.一个实例的静态变量变化,这个类的其他实例的该变量同时发生变化。

静态方法是通过类而非类的对象调用的方法,最典型的例子是Math类:

double x=Math.sqrt(3.9);

以及单例设计模式的类实例化方法:

public static classname getInstance()

完整的例子应该是这样的:

static的加载与执行

实际上,静态变量与静态方法使用的不同只是表象,本质是static修饰符改变了代码的加载时机。

下面的例子来说明问题:

public class StaticClass {
    static{
        System.out.println("run1");
    }
    public StaticClass(){
        System.out.println("init");
    }
    static{
        System.out.println("run2");
    }
    public static void main(String[] args) {
         StaticClass sc=new StaticClass();
    }
}

输出是:

run1
run2
init

1、每调用一次构造方法,则执行一次构造块
2、静态块只在类加载的时候加载一次
3、有多个静态变量或块时,按声明顺序加载

通过static关键词实现单例设计模式


/**
 * 演示单例设计模式
 * @author reus
 * 1,私有化构造器,避免外部直接创建
 * 2,声明私有静态的类对象,初始设置为空
 * 3,创建对外的静态方法,判断对对象是否为空,如果为空,调用私有的创建方法
 */

public class Singleton {

    //1,私有化构造器,避免外部直接创建
    private Singleton(){

    }

    //2,声明私有静态的类对象,初始设置为空
    private static Singleton instance=null;

    //3,创建对外的静态方法,判断对对象是否为空,如果为空,调用私有的创建方法
    public static Singleton getInstance(){
        if(instance==null){
            instance=new Singleton();
        }
        return instance;
    }

}

public class test
{
    public static void main(String[] args)
    {
        Singleton s1=Singleton.getInstance();//调用getInstance()实例化
        Singleton s2=Singleton.getInstance();
        System.out.println(s1==s2);//通过输出可以看到实际上s1和s2是同一个对象
    }
}

通过这样的设计,可以设定一个类只有一个实例化,这样的设计方法也叫做单例模式。这样的功能实际上也可以使用一个int型数字作为标记,然后可以是一个类实例化不超过一个或几个,但显然使用static更高端一点。

但这个设计存在一个漏洞,那就是公共实例方法不是同步方法,这意味着,如果多个线程调用这个方法,可能会出现创建了多个实例的错误情况。使用synchronized关键字,加强上述代码:

/**
 * 演示单例设计模式
 * @author reus
 * 1,私有化构造器,避免外部直接创建
 * 2,声明私有静态的类对象,初始设置为空
 * 3,创建对外的静态方法,判断对对象是否为空,如果为空,调用私有的创建方法
 * *用synchronized关键词强化安全性
 */

public class Singleton {

    //1,私有化构造器,避免外部直接创建
    private Singleton(){

    }

    //2,声明私有静态的类对象,初始设置为空
    private static Singleton instance=null;

    //3,创建对外的静态方法,判断对对象是否为空,如果为空,调用私有的创建方法
    public static Singleton getInstance(){
        if(instance==null){//已经有实例,直接返回,提高效率
            synchronized (Singleton.class) {//*用synchronized关键词强化安全性
                if(instance==null){//确保安全性
                    instance=new Singleton();
                }
            }
        }
        return instance;
    }

}

上述代码演示的都是“懒汉式”单例模式,还有一种“恶汉式”单例模式,两者区别在于:

懒汉式:在声明私有静态的类对象,初始设置为空;
饿汉式:在类中声明静态类对象时直接初始化了一个实例。

/**
 * 演示单例设计模式
 * @author reus
 * 1,饿汉式实现:在类中声明静态类对象时直接初始化了一个实例
 * 2,在对外的实例方法中,直接返回已实例化对象
 */

class Singleton2 {

    private Singleton2(){        
    }

    //1,声明私有静态的类对象——饿汉式实现:在类中声明静态类对象时直接初始化了一个实例
    private static Singleton2 instance=new Singleton2();

    //2,创建对外的静态方法,判断对对象是否为空,如果为空,调用私有的创建方法
    public static Singleton2 getInstance(){       
        return instance;
    }

}

这样做确保了一定只有一个实例,安全性更有保障,但较比懒汉式存在一个问题,就是在未使用的时候,就消耗了空间,如果这个类包含很多属性,这个消耗就值得优化。因此有了下面的小改良:

/**
 * 演示单例设计模式
 * @author reus
 * 1,饿汉式实现:在类中声明静态类对象时直接初始化了一个实例
 * 2,在对外的实例方法中,直接返回已实例化对象
 * **把实例包装在一个类里面,这样在Singleton只有一个SingletonHolder类的引用,、
 * **只有在真正外部实例化的时候,才会开辟空间,创建单例的对象
 */

class Singleton3 {

    //**把实例包装在一个类里面,这样在Singleton只有一个SingletonHolder类的引用,只有在真正外部实例化的时候,才会开辟空间,创建单例的对象
    private static class Singleton3Holder{
        //1,声明私有静态的类对象——饿汉式实现:在类中声明静态类对象时直接初始化了一个实例
        private static Singleton3 instance=new Singleton3(); 
    }
    private Singleton3(){        
    }

    //2,创建对外的静态方法,判断对对象是否为空,如果为空,调用私有的创建方法
    public static Singleton3 getInstance(){       
        return Singleton3Holder.instance;
    }

}

把实例包装在一个私用的工具类里面,这样在类中只有一个工具类的引用,只有在真正外部实例化的时候,才会开辟空间,创建类的实际对象。代码又一次提升了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值