Java面向对象之单例设计模式及final 关键字

1、单例设计模式

1.1、设计模式的定义

在这里插入图片描述

1.2、单例模式的定义

单例(单个的实例)

  1. 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法
  2. 单例模式有两种方式:
    (1)饿汉式
    (2)懒汉式
1.3、单例模式的实现
  1. 构造器私有化 => 防止直接 new
  2. 类的内部创建对象
  3. 向外暴露一个静态的公共方法
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

  1. 当不希望类被继承时,可以用final修饰
  2. 当不希望父类的某个方法被子类覆盖/重写(override)时,可以用final关键字修饰【 访问修饰符 final 返回类型 方法名 】
  3. 当不希望类的某个属性的值被修改,可以用final修饰【 public final double TAX_RATE=0.08 】
  4. 当不希望某个局部变量被修改,可以使用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() {}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值