• 第四章:单例模式与final


    系列文章目录



    前言

    单例模式与final关键字


    一、单例模式

    设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。就像是经典的棋谱,不同的棋局,我们用不同的棋谱,免去我们自己在思考和摸索。

    单例模式
    采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例并且该类只提供一个取得对象实例的方法
    单例模式有两种方式:1.饿汉式 2.懒汉式
    单例模式的实现
    1. 构造器私有化,防止直接new
    2. 类的内部创建对象并且私有化,为了能够在静态方法中,返回对象,需要将对象修饰为 static
    3. 向外暴露一个静态的公共方法:getlnstance
    package com.hspedu.single_;
    
    public class SingleTon01 {
    	public static void main(String[] args) {
    		// GirlFriend xh = new GirlFriend("小红");
    		// GirlFriend xb = new GirlFriend("小白");
    		//通过方法可以获取对象
    		GirlFriend instance = GirlFriend.getInstance();
    		System.out.println(instance);
    		
    		GirlFriend instance2 = GirlFriend.getInstance();
    		System.out.println(instance2);
    		
    		System.out.println(instance == instance2);//T
    		//System.out.println(GirlFriend.n1);
    		//...
    	}
    }
    
    //有一个类, GirlFriend
    //只能有一个女朋友
    class GirlFriend {
    
    	private String name;
    	//public static int n1 = 100;
    	//为了能够在静态方法中, 返回 gf 对象, 需要将其修饰为 static
    	//對象, 通常是重量級的對象, 餓漢式可能造成創建了對象, 但是沒有使用.
    	
    	private static GirlFriend gf = new GirlFriend("小红红");
    	//如何保障我们只能创建一个 GirlFriend 对象
    	//步骤[单例模式-饿汉式]
    	//1. 将构造器私有化
    	//2. 在类的内部直接创建对象(该对象是 static)
    	//3. 提供一个公共的 static 方法, 返回 gf 对象
    	
    	private GirlFriend(String name) {
    		System.out.println("構造器被調用.");
    		this.name = name;
    	} 
    	public static GirlFriend getInstance() {
    		return gf;
    	}
    	 
    	@Override
    	public String toString() {
    		return "GirlFriend{" + 
    		"name='" + name + '\'' + 
    		'}' ;
    	}
    
    }
    
    
    • 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
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    package com.hspedu.single_;
    
    /**
    * 演示懶漢式的單例模式
    */
    
    public class SingleTon02 {
    	public static void main(String[] args) {
    		//new Cat("大黃");
    		//System.out.println(Cat.n1);
    		Cat instance = Cat.getInstance();
    		System.out.println(instance);
    		//再次調用 getInstance
    		Cat instance2 = Cat.getInstance();
    		System.out.println(instance2);
    		System.out.println(instance == instance2);//T
    	}
    } 
    
    
    
    //希望在程序運行過程中, 只能創建一個 Cat 對象
    //使用單例模式
    class Cat {
    	private String name;
    	public static int n1 = 999;
    	private static Cat cat ; //默認是 null
    	
    	//步驟
    	//1.仍然構造器私有化
    	//2.定義一個 static 靜態屬性對象
    	//3.提供一個 public 的 static 方法, 可以返回一個 Cat 對象
    	//4.懶漢式, 只有當用戶使用 getInstance 時, 才返回 cat 對象, 後面再次調用時, 會返回上次創建的 cat 對象
    	// 從而保證了單例
    	
    	private Cat(String name) {
    		System.out.println("構造器調用...");
    		this.name = name;
    	} 
    	
    	public static Cat getInstance() {
    		if(cat == null) 
    		{//如果還沒有創建 cat 對象
    			cat = new Cat("小可愛");
    		} 
    		return cat;
    	} 
    	
    	@Override
    	public String toString() {
    		return "Cat{" +
    		"name='" + name + '\'' +
    		'}';
    	}
    }
    
    • 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
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    饿汉式vs懒汉式
    二者最主要的区别在于创建对象的时机不同:饿汉式是在类加载就创建了对象实例而懒汉式是在使用时才创建
    饿汉式不存在线程安全问题,懒汉式存在线程安全题,(后面学习线程后,会完善一把)
    饿汉式存在浪费资源的可能。因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象就浪费了,懒汉式是使用时才创建,就不存在这个问题
    在我们javaSE标准类中,java.lang.Runtime就是经典的单例模式

    二、final 关键字

    final:最后的,最终的。可以修饰类、属性、方法和局部变量。

    final用法
    1. 当不希望类被继承时,可以用final修饰
    2. 当不希望父类的某个方法被子类覆盖/重写(override)时,可以用final关键字修饰
    3. 当不希望类的的某个属性的值被修改,可以用final修饰
    4. 当不希望某个局部变量[方法体内的形参]被修改,可以使用final修饰
    package com.hspedu.final_;
    
    public class Final01 {
    	public static void main(String[] args) {
    		E e = new E();
    		//e.TAX_RATE = 0.09;
    	}
    } 
    //如果我们要求 A 类不能被其他类继承
    //可以使用 final 修饰 A 类
    final class A { }
    
    //class B extends A {}
    class C {
    	//如果我们要求 hi 不能被子类重写
    	//可以使用 final 修饰 hi 方法
    	public final void hi() {}
    } 
    
    class D extends C {
    	// @Override
    	// public void hi() {
    	// System.out.println("重写了 C 类的 hi 方法..");
    	// }
    } 
    
    //当不希望类的的某个属性的值被修改,可以用 final 修饰
    class E {
    	public final double TAX_RATE = 0.08;//常量
    } 
    
    //当不希望某个局部变量被修改, 可以使用 final 修饰
    class F {
    	public void cry() {
    		//这时, NUM 也称为 局部常量
    		final double NUM = 0.01;
    		//NUM = 0.9;
    		System.out.println("NUM=" + NUM);
    	}
    }
    
    
    
    • 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
    • 42
    final使用细则part1
    final修饰的属性又叫常量,一般用XX_XX_XX来命名
    final修饰的属性在定义时,必须赋初值并且以后不能再修改,赋值可以在如下位置之一【选择一个位置赋初值即可]: 定义时/在构造器中/在代码块中
    如果final修饰的属性是静态的,则初始化的位置只能是:定义时/在静态代码块不能在构造器中赋值
    final类不能继承,但是可以实例化对象
    如果类不是final类,但是含有final方法, 则该方法虽然不能重写,但是可以被继承
    package com.hspedu.final_;
    
    public class FinalDetail01 {
    	public static void main(String[] args) {
    		CC cc = new CC();
    		new EE().cal();
    	}
    } 
    
    class AA {
    	/*
    	1. 定义时: 如 public final double TAX_RATE=0.08;
    	2. 在构造器中
    	3. 在代码块中
    	*/
    	public final double TAX_RATE = 0.08;//1.定义时赋值
    	public final double TAX_RATE2 ;
    	public final double TAX_RATE3 ;
    	
    	public AA() {//构造器中赋值
    		TAX_RATE2 = 1.1;
    	} 
    	{
    	//在代码块赋值
    		TAX_RATE3 = 8.8;
    	}
    } 
    
    class BB {
    	/*
    	如果 final 修饰的属性是静态的, 则初始化的位置只能是
    	1 定义时 2 在静态代码块 不能在构造器中赋值。
    	*/
    	public static final double TAX_RATE = 99.9;
    	public static final double TAX_RATE2 ;
    	static {
    		TAX_RATE2 = 3.3;
    	}
    } 
    
    //final 类不能继承, 但是可以实例化对象
    final class CC { }
    
    //如果类不是 final 类, 但是含有 final 方法, 则该方法虽然不能重写, 但是可以被继承
    //即, 仍然遵守继承的机制.
    class DD {
    	public final void cal() {
    		System.out.println("cal()方法");
    	}
    } 
    
    class EE extends DD { }
    
    
    • 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
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    final使用细则part2
    一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法
    final不能修饰构造方法(即构造器)
    final和static往往搭配使用,效率更高,不会导致类的加载,底层编译器做了优化处理
    包装类(Integer,Double,Float,Boolean等都是final),String也是final类
    package com.hspedu.final_;
    
    public class FinalDetail02 {
    	public static void main(String[] args) {
    		System.out.println(BBB.num);
    		//包装类,String 是 final 类, 不能被继承
    	}
    } 
    
    //final 和 static 往往搭配使用, 效率更高, 不会导致类加载.底层编译器做了优化处理
    class BBB {
    	public final static int num = 10000;
    	
    	static {
    		System.out.println("BBB 静态代码块被执行");
    	} 
    }
    
    final class AAA{
    	//一般来说, 如果一个类已经是 final 类了, 就没有必要再将方法修饰成 final 方法
    	//public final void cry() {}
    	
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    总结

    单例模式是非常通用的类设计模式,final关键字经常与static关键字搭配使用。

  • 相关阅读:
    RootSIFT---SIFT图像特征的扩展
    Python算法——树的序列化与反序列化
    线性代数对角化
    LDcad零件新增与导入
    第十三届蓝桥杯大赛软件赛决赛(Java 大学B组)
    Hudi源码|bootstrap源码分析总结(写Hudi)
    【MySQL】高性能高可用设计实战-索引篇
    PE结构学习(2)_PE结构的组成
    Postman:完整指南
    MySQL:函数
  • 原文地址:https://blog.csdn.net/yanyongfu523/article/details/134390786