文章目录
1、单例设计模式
1.1、设计模式的定义
1.2、单例模式的定义
单例(单个的实例)
- 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法
- 单例模式有两种方式:
(1)饿汉式
(2)懒汉式
1.3、单例模式的实现
- 构造器私有化 => 防止直接 new
- 类的内部创建对象
- 向外暴露一个静态的公共方法
1.3.1、饿汉式
package SingleTon01;
public class SingleTon01 {
public static void main(String[] args) {
// GirlFriend xb = new GirlFriend("小白"); // 报错了 构造器是private, 不允许 new
// GirlFriend xh = new GirlFriend("小灰"); // 报错了 构造器是private, 不允许 new
GirlFriend instance1 = GirlFriend.getInstance();
System.out.println(instance1);
GirlFriend instance2 = GirlFriend.getInstance();
System.out.println(instance2);
System.out.println(instance1 == instance2); // true
System.out.println(instance1.n1); // 100
System.out.println(instance2.n1); // 100
}
}
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.3.2、懒汉式
package SingleTon01;
public class SingleTon02 {
public static void main(String[] args) {
// new Cat("大黃"); // 报错 构造器是private
System.out.println(Cat.n1); // 999
Cat instance1 = Cat.getInstance();
System.out.println(instance1);
// 再次调用 getInstance
Cat instance2 = Cat.getInstance();
System.out.println(instance2);
System.out.println(instance1 == instance2); // true
}
}
// 希望在程序运行过程中,只能创建一个 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.3.3、饿汉式 VS 懒汉式
2、final 关键字
2.1、定义
final 中文意思:最后的、最终的
final 可以修饰类、属性、方法和局部变量
在某些情况下,程序员可能有以下需求会使用到final
- 当不希望类被继承时,可以用final修饰
- 当不希望父类的某个方法被子类覆盖/重写(override)时,可以用final关键字修饰【 访问修饰符 final 返回类型 方法名 】
- 当不希望类的某个属性的值被修改,可以用final修饰【 public final double TAX_RATE=0.08 】
- 当不希望某个局部变量被修改,可以使用final修饰【 final double TAX_RATE=0.08 】
package final_;
public class final_ {
public static void main(String[] args) {
E e = new E();
System.out.println(e.TAX_RATE); // 0.08
// e.TAX_RATE = 0.09; // 报错
new F().cry();
}
}
// 如果我们要求 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); // NUM=0.01
}
}
2.2、final 使用注意事项和细节讨论
package FinalDetail01;
public class FinalDetail01 {
public static void main(String[] args) {
CC cc = new CC();
new EE().cal(); // cal()方法
}
}
class AA {
/*
1. 定义时: 如 public final double TAX_RATE=0.08;
2. 在构造器中
3. 在代码块中
*/
public final double TAX_RATE = 0.08; // 定义时赋值
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 {
}
package FinalDetail01;
public class FinalDetail02 {
public static void main(String[] args) {
System.out.println(BBB.num); // 10000
// 包装类, 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() {}
}