• 高级开发要会高效Java


    高级开发起码得会些高级技巧吧?那这些高级技巧从哪里取得呢?

    第一种方式肯定是读书,什么?你没那么多时间?

    幸好,我这里忙你开启了速读模式,跟着我一起学习 《高效Java》系列。

    咱们第一站就来到了: 静态工厂方法

    1. 什么是静态工厂方法?

    • 静态工厂方法是一种创建对象的方式。

    • 这里的静态工厂方法,并不是设计模式中的工厂模式

    • 静态工厂方法仅仅是类的一个普通的静态方法,它的最终效果等同于构造器。

    说了这么多,给你举个例子就明白了。

    1. Integer integer = Integer.valueOf("1");
    2. Boolean aBoolean = Boolean.valueOf(true);
    3. Calendar calendar = Calendar.getInstance();
    4. 复制代码

    上面的例子中 valueOfgetInstance 方法就被称为 静态工厂方法

    2. 静态工厂方法优势

    那么为什么鼓励用静态工厂方法来创造对象,而不是鼓励使用构造器呢?

    原因有如下几点:

    • 静态工厂方法拥有名称,而构造器没有

    • 不必在每次调用静态工厂方法时都创建一个对象

    • 可以返回当前类的任何子类型对象

    • 减少使用者出错的概率

    下面我们来逐一了解这些优点:

    2.1 静态工厂方法拥有名称,而构造器没有

    因为构造器的本身并没有确切的描述被返回的对象,而静态工厂方法因为有方法名,所以他能够更为清楚的描述将被返回的对象。尤其是拥有多个不同参数的构造方法,在选择构造方法的时候,会让人有些迷惑,而静态工厂方法则更加清楚明了。

    1. //Date类
    2. Date date0 = new Date();
    3. Date date1 = new Date(2022L);
    4. Date date2 = new Date("2022");
    5. Date date3 = new Date(2022,3,20);
    6. Date date4 = new Date(2022,3,20,18,30,59);
    7. // LocalDate类
    8. public static LocalDate now(){}
    9. public static LocalDate ofEpochDay(long epochDay){}
    10. public static LocalDate of(int year, Month month, int dayOfMonth) {}
    11. 复制代码

    看下这么多不同参数的构造方法,如果不去了解Date,懵不懵? 再看看 Java8 中的LocalDate类。

    2.2 不必在每次调用静态工厂方法时都创建一个对象

    构造器每次调用的时候都会创建一个新的对象,而使用静态工厂方法则可以不必每次都创建新的对象,我们可以提前创建好对象或重用已有的对象,以达到提升性能的目的。

    来我给你们举个例子:

    1、Integer 类中的 valueOf 方法,当数值在 -128 ~ 127之间时,是不会创建新的Integer类的,而是从缓存中取出。

    1. public static Integer valueOf(int i) {
    2. if (i >= IntegerCache.low && i <= IntegerCache.high)
    3. return IntegerCache.cache[i + (-IntegerCache.low)];
    4. return new Integer(i);
    5. }
    6. 复制代码

    2、Boolean 类中的 valueOf 方法,直接取出提前创建好的静态常量返回,也没有创建新的对象。

    1. public final class Boolean{
    2. public static final Boolean TRUE = new Boolean(true);
    3. public static final Boolean FALSE = new Boolean(false);
    4. public static Boolean valueOf(boolean b) {
    5. return (b ? TRUE : FALSE);
    6. }
    7. }
    8. 复制代码

    2.3 可以返回原类型的任何子类型对象

    这里牵涉到最基础的多态:

    • 向上转型:多态本身就是向上转型过的过程

      使用格式:父类类型 变量名=new 子类类型();

    还有就是设计模式六大原则中的<里氏替换原则>:

    • 任何使用父类的地方都能替换成子类来使用。
    1. public class Test {
    2. //静态工厂方法,返回Test的子类型T1
    3. public static Test valueOf(){
    4. return new T1();
    5. }
    6. private static class T1 extends Test{}
    7. }
    8. 复制代码

    虽然可以这样用,但是不建议这样使用,因为这样不利于解耦,父类最好不要依赖于子类。

    推荐的做法是:像 Collections 类一样,它像一个工具类,它提供了许多静态工厂方法,你去看会发现静态工厂方法返回的并不是确定的类型,而是List接口的一些子类,这些子类被作为私有类定义在Collections 中,我们无法直接构造这些类,但却可以通过静态工厂方法使用它。

    这样做的目的是精减API的数量,对客户端来说也是一种减压。我们有时不必知道返回的类是什么,但我们可以像我们熟知的接口一样使用它。

    1. // SingletonList 是私有的,实现List接口的类
    2. public static <T> List<T> singletonList(T o) {
    3. return new SingletonList<>(o);
    4. }
    5. // EmptyList 是私有的,实现List接口的类
    6. public static final <T> List<T> emptyList() {
    7. return (List<T>) EMPTY_LIST;
    8. }
    9. 复制代码

    2.4 减少使用者出错的概率

    先看下例子:

    1. class Run {
    2. public static final int RUNNING = 1;
    3. public static final int STOP = 2;
    4. protected int state;
    5. public Run(int state) {
    6. this.state = state;
    7. }
    8. public void process(){
    9. // if RUNNING / STOP
    10. }
    11. }
    12. 复制代码

    上面例子中,我只想对 RUNNING / STOP 两种状态处理,但我却无法控制使用者的行为,比如他可以这样调用:new Run(4)

    这种情况怎么办呢?

    1. class Run {
    2. public static final int RUNNING = 1;
    3. public static final int STOP = 2;
    4. protected int state;
    5. //私有构造方法外部无法调用
    6. private Run(int state) {
    7. this.state = state;
    8. }
    9. public static Run running(){
    10. return new Run(RUNNING);
    11. }
    12. public static Run stop(){
    13. return new Run(STOP);
    14. }
    15. public void process(){
    16. // if RUNNING / STOP
    17. }
    18. }
    19. 复制代码

    经过这样改造后,我们严格控制了取值范围,使用者出错的机会就大大减少了。

    3. 总结

    作为类的提供者,我们要尽量确保自身性能好,具有灵活性,让使用者使用起来更容易,更不容易出错。

    恰恰静态工厂方法可以让我们做到这些,所有建议创建对象的时候优先考虑使用静态工厂方法。

     

  • 相关阅读:
    测试平台部署三——Nginx
    机器学习实战:Python基于EM期望最大化进行参数估计(十五)
    音视频入门基础:H.264专题(14)——计算视频帧率的公式
    Greenplum性能优化之路
    王道考研——操作系统(第二章 进程管理)(进程;线程)
    分布式事务 实战 - Seata配置Nacos注册中心和配置中心
    设计模式:工厂方法模式(C#、JAVA、JavaScript、C++、Python、Go、PHP):
    多级CMakeLists.txt调用
    python3.8,torch1.10.2+cu113、torch-geometric 安装
    【java学习】项目: ATM系统
  • 原文地址:https://blog.csdn.net/m0_67698950/article/details/126430700