A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

单例设计模式

思想

解决问题:保证一个类的对象在内存中的唯一性。
应用场景:多个程序都在操作同一个配置文件时,需要程序A操作后的结果,程序B要知道并继续基于A操作后的结果进行操作。
前提:数据都存储在配置文件对象中,要求程序A和程序B操作的配置文件对象是同一个。
怎么实现呢?
怎么可以保证这个类只能产生一个对象呢?
思路:
1.问题是其他程序都可以通过new创建该类的对象。无法控制数量。
所以不让其他程序new就可以了。
2.那第一步的问题也产生了,那其他程序不就没有对象了么?
干脆,在本类中自己new一个本类对象。这样的好处是,不让别的程序new,自己new,可以实现数量控制。
3.对外提供让其他程序获取该对象的方式,就可以了。

体现(代码)

步骤:
1.不让其他程序new该类对象,怎么办?
可以将类中的构造函数私有化。
2.在本类中new一个对象。
3.定义一个方法返回该对象。

class Single {
          //创建一个本类对象
         static Single s=new Single();
         
          //构造函数私有化
         private Single() {}
         
         //定义一个方法返回该对象。让其他程序可以获取到。
          static Single getInstance()
          {
                  return s;
          }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public class SingleDemo {
       
         public static void main(String[] args)
           {          
            //     new Single();
             Single s1=Single.getInstance();
             Single s2=Single.getInstance();
             System.out.println(s1==s2);
           }
}
1
2
3
4
5
6
7
8
9
10
结果

true
1
内存图解


代码细节

class Single {
          //创建一个本类对象
         private static Single s=new Single();
         
          //构造函数私有化
         private Single() {}
         
         //定义一个方法返回该对象。让其他程序可以获取到。之所以定义访问,就是为了可控。
         public static Single getInstance()//为了加强别的程序对它的访问,加public
          {
                if(num<0)
                {
                    return null;
                }
                  return s;
          }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class SingleDemo {
       
         public static void main(String[] args)
           {          
            //     new Single();
           //Single s1=Single.getInstance();
           //Single s2=Single.getInstance();
           Single s1=Single.s;
           Single s2=Single.s;//s是静态成员变量,可以用类调用。和上一种在结果上是没有区别的。
                                    //所以可以把static Single getInstance() { return s; }去掉。但用方法可以控制。
             System.out.println(s1==s2);
           }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
饿汉和(懒汉——单例的另一种形式)

上一种是随着类的加载,对象被创建。
这一种是调用了类的方法后,才创建了对象。
该形式是延迟了加载方式。

class Single {
        //创建一个本类成员
         private static Single s=null;
         
          //构造函数私有化
         private Single() {}
         
         //定义一个方法返回该对象。让其他程序可以获取到。之所以定义访问,就是为了可控。
         public static Single getInstance()
          {
                 if(s==null)
                      s=new Single();//
                 return s;
          }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class SingleDemo {
       
         public static void main(String[] args)
           {          
            //     new Single();
           //Single s1=Single.getInstance();
           //Single s2=Single.getInstance();
           Single s1=Single.s;
           Single s2=Single.s;//s是静态成员变量,可以用类调用。和上一种在结果上是没有区别的。
                                    //所以可以把static Single getInstance() { return s; }去掉。但用方法可以控制。
             System.out.println(s1==s2);
           }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
应用

class SuperMan {         
         private String name;
         SuperMan(String name)
         {
                 this.name=name;
         }
         public void setName(String name)
         {
                 this.name=name;                 
         }
         public String getName()
         {
                return this.name;                 
         }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class SingleDemo {
         public static void main(String[] args)
           {          
            SuperMan s1=new SuperMan("克拉克");
            s1.getName();            
            SuperMan s2=new SuperMan("英雄");
            s2.getName();
           }
}
1
2
3
4
5
6
7
8
9
克拉克就是英雄 ,但这时相当于创建了两个对象,所以不合理。
改成:

class SuperMan {       
         private  String name;
         private static SuperMan man=new SuperMan("克拉克");
         
         public SuperMan (String name)//为了加强别的程序对它的访问,加public
          {        
                  this.name=name;
          }
         public static SuperMan getInstance()//为了加强别的程序对它的访问,加public
          {        
                  return man;
          }
     public  void setName(String name) {
             this.name=name;
           
     }

     public String getName() {
     return this.name;
     }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class SingleDemo {       
         public static void main(String[] args)
           {       
                 SuperMan s1=SuperMan.getInstance();
                 s1.getName();
                 
                 SuperMan s2=SuperMan.getInstance();
                 s2.setName("英雄");
                 s2.getName();
           }
}
1
2
3
4
5
6
7
8
9
10
11
继承

概念&特点

继承:
1.提高了代码的复用性。
2.让类与类之间产生了关系。为第三个特征多态提供了前提。

//将学生和工人的共享代码向上抽取到一个共性的类型中。这个类型中既包括学生和工人,
public class Person {//父类。超类。基类。
     String name;
     int age;
}
//描述学生。属性:姓名,年龄,行为:学习。让学生和Person产生关系,就可以让学生使用Person中的共性的内容。
//通过一个关键字extends继承
class Student extends Person//子类
{       
         //String name;
         //int age;
         void study() {
                 System.out.println("good good");
         }       
}
//描述工人。属性:姓名,年龄。行为:工作。
class worker extends Person1
{       
         String name;
         int age;
         void work() {
                 System.out.println("hard");
         }
}
//描述工人。属性:姓名,年龄。行为:工作。
class worker extends Person1
{       
         String name;
         int age;
         void work() {
                 System.out.println("hard");
         }
}
public class ExtendsDemo {
    public static void main(String[] args) {
            Student s=new Student();
            s.name="小明";
        s.age=14;
        s.study();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
单继承&多继承

Java支持单继承,不直接支持多继承。
单继承:一个类只能有一个父类。
多继承:一个类可以有多个父类。Java并不直接支持。
优势:可以让子类具备更多的功能。
弊端:调用的不确定性,因为方法的主体不同。java对其进行改良。
举例:
加入可以多继承

class Fu1
{
    void show()
    {
          sop("fu1 show")
    }
}
class Fu2
{
    void show()
    {
          sop("fu2 show")
    }
}
class Z1 extends Fu1,Fu2
{
    void show()
    {
          new Z1().show();
    }
}
//这里有一个问题:show是show的Fu1还是Fu2?
//出现调用的不确定性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
当出现多层次继承:


什么时候定义继承

当事物之间存在着所属(is a)关系时,可以通过继承来体现这个关系。
xxx是yyy中一种,xxx extends yyy.

class Demo1
{
     void method1() {}
     void method2() {}
}
class Demo2
{
     void method1() {}
     void method3() {}
}
1
2
3
4
5
6
7
8
9
10
此时Demo2不能继承Demo1.因为Demo2没有继承Demo1的所有功能。
Demo2可以获取到Demo1中的method1,但是不应该具备的method2,不存在继承。
但是Demo1、Demo2具备共性。抽取。

class Demo
{
  void method1(){}
}
class Demo1 extends Demo
{
     void method2() {}
}
class Demo2 extends Demo
{
     void method3() {}
}
new Demo1.method1();?可以
new Demo1.method2();?可以
new Demo1.method3();?不可以
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
继承-私有的访问

如果在概念&特点那一章节中

public class Person {
     private String name;
     int age;
}
1
2
3
4
那么在ExtendsDemo中还可不可以调用name?
这是一个细节:对于父类中私有的部分,子类对象是无法直接访问的。
但子类还是具备父类那个私有的部分。

继承-成员变量的特点

子父类出现后,代码上的一些特点。
1.成员变量。
2.成员函数。
3.构造函数。

public class Fu {
     int num=4;
}
class Zi extends Fu
{       
        int num2=5;
        void show()
        {
                int num3=6;
                System.out.println("num="+num);
                System.out.println("num2="+num2);
                System.out.println("num3="+num3);
        }       
}
public class ExtendsDemo2 {
    public static void main(String[] args) {
            new Zi().show();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
结果:

num=4;
num=5;
num=6;
1
2
3
如果把上述的Zi改成 ``` class Zi extends Fu {        int num=5; void show() { int num=6; System.out.println("num="+num); }        } ``` 结果
num=6//先是局部变量
1
怎么让结果=5?
当局部变量和成员变量重复时,用this区分

class Zi extends Fu
{       
        int num=5;
        void show()
        {
                int num=6;
                System.out.println("num="+this.num);
        }       
}
1
2
3
4
5
6
7
8
9
结果:

num=5
1
如何让结果=4?
当子父类中的出现了同名的成员变量,用关键词super来区分。

class Zi extends Fu
{       
        int num=5;
        void show()
        {
                int num=6;
                System.out.println("num="+super.num);
        }       
}
1
2
3
4
5
6
7
8
9
结果:

num=4
1
但这样用super其实挺少的。

super关键字

super和this的用法很相似。
this:代表的是本类的对象引用。可以System.out.println(this)
super:代表的是父类的那片空间。不可以System.out.println(super).super后一定要加“.”或者()。
Zi在方法区有一个super指向Fu,在建立对象后,Fu与Zi的num都存在于堆中。也就是说有两个num。


继承-成员函数的特点(覆盖)

子父类中的方法的特点:

public class Fu {
     void show() {
             System.out.println("fu show run");
     }
}
class Zi extends Fu
{       
        void show1()
        {
                System.out.println("zi show run");               
        }
}
public class ExtendsDemo3 {
    public static void main(String[] args) {
            Zi z=new Zi();
            z.show();
            z.show1();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
结果:

fu show run
zi show run
1
2
内存图


特殊情况:
当子父类中出现的一模一样的方法时。
子类对象运行的是子类的方法。
这种特殊情况,称之为覆盖(override)。覆写、重写。
覆盖返回值类型,函数名,参数列表都一致。

public class Fu {
     void show() {
             System.out.println("fu show run");
     }
}
class Zi extends Fu
{       
        void show()
        {
                System.out.println("zi show run");               
        }
}
public class ExtendsDemo3 {
    public static void main(String[] args) {
            Zi z=new Zi();
            z.show();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
结果:

zi show run
1
因为直接找到子类中的方法,运行即可。不用再找父类中的。

覆盖的应用

class Phone {
    public void call() {
    System.out.println("fu show run");
     }
    public void sendMsg() {
            System.out.println("fu show run");
    }
    public void show() {
            System.out.println("number");
    }
}
class NewPhone extends Phone
{       
         //定义了来电显示功能.注意:父类已经定义了来电显示功能。子类直接拿过来用就行。
         //但是子类对功能的内容要有自己的定义。保留父类功能的声明,建立子类功能特有的内容,这就是覆盖的应用。
                public void show() {
                //System.out.println("number");
                super.show();
                System.out.println("name");
                System.out.println("pic");
                }       
}
public class ExtendsDemo3 {
    public static void main(String[] args) {
            NewPhone p=new NewPhone();
            p.show();
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
覆盖的注意事项

1.子类方法覆盖父类方法,必须要保证权限大于等于父类权限。
2.静态只能覆盖静态,或者被静态覆盖。
成员变量不可能存在覆盖,覆盖只是函数的。

继承-子类的实例化过程

子父类中构造函数的特点。
就会发现,创建子类对象时,Fu中的空参数构造函数也运行了?
因为子类中所有的构造函数的第一行默认都有一个隐式的super();语句。
调用本类中的构造函数用this(实参列表)语句。调用父类中的构造函数用super(实参列表);

为什么子类对象初始化都要访问父类中的构造函数呢?
因为子类继承了父类中的内容,所以创建对象时必须要先看父类是如何对内容进行初始化的。

这就是子类的实例化过程。

class Fu extends Object
{
   int num;
   Fu()
   {
          //super();
            num=4;
             System.out.println("fu run");
   }
}
class Zi extends Fu
{       
       //super();
         Zi(){
                 System.out.println("zi run");
         }
}
public class ExtendsDemo3 {
    public static void main(String[] args) {
            Zi z=new Zi();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
结果:

fu run
zi run
1
2
继承-子类的实例化过程(注意事项)

第一种:

class Fu extends Object
{
   int num;
   Fu()
   {
            num=4;
             System.out.println("fu run");
   }
    Fu(int x)
   {
        System.out.println("fu run…"+x);
   }
}

class Zi extends Fu
{       
         Zi(){
                 System.out.println("zi run");
         }
         Zi(int x)
     {
         //super();
          System.out.println("fu run…"+x);
      }
}

public class ExtendsDemo3 {
    public static void main(String[] args) {
            Zi z=new Zi(5);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
输出:

fu run
zi run…5
1
2
第二种
当父类中没有空参数构造函数时,子类需要通过显示定义super语句指定要访问的fu

class Fu extends Object
{
   int num;
    Fu(int x)
   {
        System.out.println("fu run…"+x);
   }
}

class Zi extends Fu
{       
         Zi(){
             //super();
                 System.out.println("zi run");
         }
         Zi(int x)
     {
         //super();
          System.out.println("fu run…"+x);
      }
}

public class ExtendsDemo3 {
    public static void main(String[] args) {
            Zi z=new Zi(5);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
结果报错:因为在Fu类已经自定义了构造函数,下面的Zi类又没有空参可调用,两者相互矛盾。
但不能在Fu类直接加空参Fu();
---------------------
【转载】仅作分享,侵删
作者:ChunyeLi
原文:https://blog.csdn.net/sinat_32512123/article/details/84955497


2 个回复

倒序浏览
奈斯
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马