黑马程序员技术交流社区

标题: 谁能给我讲解一下java的单例模式 [打印本页]

作者: lucky_xingxing    时间: 2011-12-12 15:11
标题: 谁能给我讲解一下java的单例模式
求助高手讲解 单例模式, 我自己理解的是 单例模式就是  静态的。只要加上static的都属于单例模式,因为静态变量从程序启动就加在到静态内存域里面,所以只有一个实例。  还有求讲解   静态块的使用方法。

该贴已经同步到 lucky_xingxing的微博
作者: 李振元    时间: 2011-12-12 15:30
单例模式:分为饿汉式和懒汉式两种。
1、两者都需要将构造方法私有化。
2、然后创建一个静态实例,这个实例随着类加载而加载,并且只加载一次。
3、对外提供获取该实例的方法:一般为getInstance()

而懒汉式和饿汉式的区别在于,实例创建的时间:
懒汉式比较懒,它指需要创建时再创建。
饿汉式随着类加载时,立刻就创建一个实例。
看毕老师的视频说:一般推荐使用饿汉式,这个没有多线程问题的考虑,比较简单。虽然效率较之懒汉式较差一点。

静态块使用:
1、作用:初始化类的成员
例如:
public class Person{
   private String name;
   private int age ;

  static {
      name = "haha";
      age = 30;
      System.out.println("hhaha");
  }
}

2、静态代码块在项目启动时就被调用,这在jdbc中有很好的应用,以后会学到的
作者: 刘基军    时间: 2011-12-12 15:46

  1. 1.
  2. //饿汉式
  3. class Single
  4. {                       
  5.         private static Single s = new Single();
  6.         private Single()
  7.         {}
  8.                public static Single getInstance()
  9.                 {
  10.                 return s;
  11.         }            
  12. }

  13. //懒汉式-(存在多线程安全问题)
  14. class Single
  15. {                       
  16.         private static Single s;
  17.         private Single()
  18.         {}
  19.                 public static Single getInstance()
  20.                 {
  21.                     if(s==null)
  22.                     {
  23.                         s = new Single();
  24.                     }               
  25.                     return s;
  26.         }            
  27. }
复制代码
2.静态代码块的使用方法,尚未接触。其运行时间:当所属类被JVM加载时,就会被调用
作者: t_mac    时间: 2011-12-12 15:52
本帖最后由 t_mac 于 2011-12-13 10:23 编辑

单例模式分两种:懒汉式单例,饿汉式单例

单例模式有一下特点:
        单例类只能有一个实例
        单例类必须自己创建自己的唯一实例
        单例类必须给所有其他对象提供这一实例
/**
*  
* 懒汉式单例在类加载的时候不创建单例实例.
* 只有在第一次请求实例的时候创建,并且只在第一次创建后,以后不再创建该类的实例
*/  
public class LazySingleton {  
    //私有静态对象,加载时候不做初始化  
    private static LazySingleton m_intance = null;  
    //私有构造方法,避免外部创建实例  
    private LazySingleton(){};  
    //静态工厂方法,返回此类的唯一实例.当发现实例没有初始化的时候,才初始化  
    synchronized public static LazySingleton getInstance(){  
        if(m_intance == null){  
            System.out.println("创建");  
            m_intance = new LazySingleton();  
        }  
        return m_intance;  
    }  
}  

/**
* 饿汉式单例在类被加载的时候,唯一实例已经被创建。这个设计模式在Java中容易实现,在别的语言中难以实现。
*
*/  
public class EagerSingleton {  
    //私有的(private)唯一(static final)实例成员,在类加载的时候就创建好了单例对象  
    private static final EagerSingleton m_instance = new EagerSingleton();  
    //私有构造方法,避免外部创建实例  
    private EagerSingleton(){};  
    //静态工厂方法,返回此类的唯一实例  
    public static EagerSingleton getInstance(){  
        return m_instance;  
    }  
}  


静态代码块块的理解:
一个类可以使用不包含在任何方法体中的静态代码块,当类被载入时,静态代码块被执行,且只被执行一次,静态块常用来执行类属性的初始化。例如:
static
{
}

类装载步骤
在Java中,类装载器把一个类装入Java虚拟机中,要经过三个步骤来完成:装载、链接和初始化,其中链接又可以分成校验、准备和解析三步,除了解析外,其它步骤是严格按照顺序完成的,各个步骤的主要工作如下:

装载:查找和导入类或接口的二进制数据;
链接:执行下面的校验、准备和解析步骤,其中解析步骤是可以选择的;
校验:检查导入类或接口的二进制数据的正确性;
准备:给类的静态变量分配并初始化存储空间;
解析:将符号引用转成直接引用;
初始化:激活类的静态变量的初始化Java代码和静态Java代码块。
初始化类中属性是静态代码块的常用用途,但只能使用一次。
静态代码块的初始化顺序
class Parent {  
    static String name = "hello";  
    {  
        System.out.println("parent block");  
    }  
    static {  
        System.out.println("parent static block");  
    }  
  
    public Parent() {  
        System.out.println("parent constructor");  
    }  
}  
  
class Child extends Parent {  
    static String childName = "hello";  
    {  
        System.out.println("child block");  
    }  
    static {  
        System.out.println("child static block");  
    }  
  
    public Child() {  
        System.out.println("child constructor");  
    }  
}  
  
public class StaticIniBlockOrderTest {  
  
    public static void main(String[] args) {  
        new Child();// 语句(*)  
    }  
}  

分析:当执行new Child()时,它首先去看父类里面有没有静态代码块,如果有,它先去执行父类里面静态代码块里面的内容,当父类的静态代码块里面的内容执行完毕之后,接着去执行子类(自己这个类)里面的静态代码块,当子类的静态代码块执行完毕之后,它接着又去看父类有没有非静态代码块,如果有就执行父类的非静态代码块,父类的非静态代码块执行完毕,接着执行父类的构造方法;父类的构造方法执行完毕之后,它接着去看子类有没有非静态代码块,如果有就执行子类的非静态代码块。子类的非静态代码块执行完毕再去执行子类的构造方法,这个就是一个对象的初始化顺序。

总结:
对象的初始化顺序:首先执行父类静态的内容,父类静态的内容执行完毕后,接着去执行子类的静态的内容,当子类的静态内容执行完毕之后,再去看父类有没有非静态代码块,如果有就执行父类的非静态代码块,父类的非静态代码块执行完毕,接着执行父类的构造方法;父类的构造方法执行完毕之后,它接着去看子类有没有非静态代码块,如果有就执行子类的非静态代码块。子类的非静态代码块执行完毕再去执行子类的构造方法。总之一句话,静态代码块内容先执行,接着执行父类非静态代码块和构造方法,然后执行子类非静态代码块和构造方法。

注意:子类的构造方法,不管这个构造方法带不带参数,默认的它都会先去寻找父类的不带参数的构造方法。如果父类没有不带参数的构造方法,那么子类必须用supper关键子来调用父类带参数的构造方法,否则编译不能通过。
作者: zoufan7410    时间: 2011-12-12 15:57

class Student
{
   private String name;
   private int age;
   private static Student s = new Student();
   // 因为getInstance方法用static修饰了,并且里面访问
   //了S ,所以S 变量也要用Static 修饰才可以。
   
    private Student(){}
    public static  Student getInstance()
    {
            //因为内存中不能建立对象,所以只有用类名.方法
            //这时想要调用getInstance时该方法要用static
           
            return s;
    }
        public String getName() {
                return name;
        }
        public void setName(String name) {
                this.name = name;
        }
        public int getAge() {
                return age;
        }
        public void setAge(int age) {
                this.age = age;
        }


}class Single
{
        private static Single s = null;
        private Single (){}
        public static Single getInstance()
        {
                if
                                if(s == null)  //这里存在安全问题 要用双重if,
                        s = new Single();
                else
                        return s;
        }
}  
作者: 胡遇潮    时间: 2011-12-12 16:25
单例模式
一个程序在运行的时候,第二个程序过来了,
但必须等第一个程序运行完,才能运行第二个程序,

静态代码块:实例化对象的时候,静态代码也跟着运行,一般是赋值

静态代码块内容先执行,接着执行父类非静态代码块和构造方法,然后执行子类非静态代码块和构造方法。


/**
* 懒汉式单例  一般推荐使用
*/  
public class Singleton
    {
        //定义一个私有的静态全局变量来保存该类的唯一实例
        private static Singleton singleton = new Singleton();

        /// 构造函数必须是私有的
        /// 这样在外部便无法使用 new 来创建该类的实例
        private Singleton()
        {
        }
        /// 定义一个全局访问点
        /// 设置为静态方法
        /// 则在类的外部便无需实例化就可以调用该方法
        public static Singleton GetInstance()
        {            
            return singleton;
        }
    }
作者: 王德云    时间: 2011-12-12 16:36
本帖最后由 王德云 于 2011-12-12 16:36 编辑
胡遇潮 发表于 2011-12-12 16:25
单例模式
一个程序在运行的时候,第二个程序过来了,
但必须等第一个程序运行完,才能运行第二个程序,


你弄错了吧,你这个是饿汉式,程序一运行就new 了一个对象,还是懒汉式吗.
开发中常用的是饿汉式,因为懒汉式加上同步会比较低效!!
作者: 胡遇潮    时间: 2011-12-12 16:44
王德云 发表于 2011-12-12 16:36
你弄错了吧,你这个是饿汉式,程序一运行就new 了一个对象,还是懒汉式吗.
开发中常用的是饿汉式,因为懒汉 ...

嗯,一着急写错了,确实是饿汉式:(
作者: 李明    时间: 2011-12-12 16:50
单例模式有两种:饿汉式和懒汉式。

懒汉式,需要创建对象时再创建。
饿汉式随着类加载时,立刻就创建一个对象。
以下是毕老师视频里写的代码:

//饿汉式。
/*
class Single
{
        private static final Single s = new Single();
        private Single(){}
        public static Single getInstance()
        {
                return s;
        }
}
*/


//懒汉式

class Single
{
        private static Single s = null;
        private Single(){}


        public static  Single getInstance()
        {
                if(s==null)
                {
                        synchronized(Single.class)
                        {
                                if(s==null)
                                        //--->A;
                                        s = new Single();
                        }
                }
                return s;
        }
}
作者: 马伟奇    时间: 2011-12-12 23:00
把构造方法前面加上private使之成为一个对象,静态方法块就是在系统运行前,先运行静态代码快




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2