单例设计模式
思想
解决问题:保证一个类的对象在内存中的唯一性。
应用场景:多个程序都在操作同一个配置文件时,需要程序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
|
|