设计模式---单例模式

来源:互联网 发布:itools 3 mac 破解版 编辑:程序博客网 时间:2024/05/16 18:46

单例模式系统中只有一个实例

两种写法:

//饿汉式,一开始就加载
 private static UserManager userManager=new UserManager();
 
 private UserManager(){}
 
 public static UserManager getInstance()
 {
  return userManager;
 }
 
 //懒汉式,延迟加载,用到时才加载,节约资源
 private static UserManager userManager=null;
 
 private UserManager(){}
 /**

synchronized 线程同步

避免发生一下错误:当两个线程同时执行这个方法时,会new出两个对象,加了它就避免了。

*/
 public static synchronized UserManager getInstance()
 {
  if(userManager==null)
  {
   userManager=new UserManager();
  }
  
  return userManager;
 }

Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。(事实上,通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效。)

 

Java的反射机制1——实例化一个对象

//教员类
public class AccpTeacher {
    private String name;

    private int age;

    public AccpTeacher() {
        name = "无名氏";
        age = 22;
    }

    public AccpTeacher(String name) {
        this.name = name;
        this.age = 22;
    }

    public String toString() {
        return "名字是:" + name;
    }

    public String toString(int age, String name) {
        this.name = name;
        this.age = age;
        return "名字是:" + name + ";年龄是:" + age;
    }
}


    如果我们实例化这个类可以用我们常用的如下方式:

public static void main(String[] args){
    AccpTeacher accpTeacher = new AccpTeacher();
    System.out.println(accpTeacher);
}

    可以清晰的想到运行结果是:名字是:无名氏
    以上是我们最常用的方式,但有时我们想通过字符串来实例化一个类如何做呢,看下面代码:

public static void main(String[] args){
    // 实例化一个类
    Object accpTeacher = Class.forName(AccpTeacher.class.getName()).newInstance();
    System.out.println(accpTeacher);
}

    运行结果同样是:名字是:无名氏
    首先Class.forName(类名)是将这个类加载到JVM虚拟机中,获得一个类型为Class的类,然后调用其newInstance()方法,相当于实例化(调用无参的构造函数);所以以上两段代码的运行效果是一致的。
    我们看到AccpTeacher这个类有一个带参数的构造方法,那如何通过反射来调用它呢?看下面代码:

public static void main(String[] args){
    // 通过构造方法实例化一个类;本例是一个有参数的构造函数,并且构造函数可以为private修饰
    Class[] argtype = new Class[] { String.class };//代表构造方法的参数类型数组
    Object[] argparam = new Object[] { "张三" };//代表构造方法的参数值数组
    Class classType = Class.forName(AccpTeacher.class.getName());
    Constructor constructor = classType.getDeclaredConstructor(argtype); //获得构造方法,argtype是参数类型数组,我们这里代表的是参数只有一个String类型
    constructor.setAccessible(true);// 访问私有构造函数,将此对象的 accessible标志设置为指示的布尔值。值为true则指示反射的对象在使用时应该取消Java语言访问检查。值为false则指示反射的对象应该实施Java语言访问检查
    Object accpTeacher2 = constructor.newInstance(argparam);
    System.out.println(accpTeacher2);
}