高级开发必会高效Java

0.png

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

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

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

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

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

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

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

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

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

Integer integer = Integer.valueOf("1");
Boolean aBoolean = Boolean.valueOf(true);
Calendar calendar = Calendar.getInstance();

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

2. 静态工厂方法优势

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

原因有如下几点:

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

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

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

  • 减少使用者出错的概率

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

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

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

//Date类
Date date0 = new Date();
Date date1 = new Date(2022L);
Date date2 = new Date("2022");
Date date3 = new Date(2022,3,20);
Date date4 = new Date(2022,3,20,18,30,59);

// LocalDate类
public static LocalDate now(){}
public static LocalDate ofEpochDay(long epochDay){}
public static LocalDate of(int year, Month month, int dayOfMonth) {}

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

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

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

来我给你们举个例子:

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

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
          return IntegerCache.cache[i + (-IntegerCache.low)];
      return new Integer(i);
}

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

public final class Boolean{
    public static final Boolean TRUE = new Boolean(true);
    public static final Boolean FALSE = new Boolean(false);
    public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
    }
}

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

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

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

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

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

  • 任何使用父类的地方都能替换成子类来使用。
public class Test {
    //静态工厂方法,返回Test的子类型T1
    public static Test valueOf(){
        return new T1();
    }
    private static class T1 extends Test{}
}

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

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

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

// SingletonList 是私有的,实现List接口的类
public static <T> List<T> singletonList(T o) {
     return new SingletonList<>(o);
}
// EmptyList 是私有的,实现List接口的类
public static final <T> List<T> emptyList() {
     return (List<T>) EMPTY_LIST;
}

2.4 减少使用者出错的概率

先看下例子:

class Run {
    public static final int RUNNING = 1;
    public static final int STOP = 2;
    protected int state;
    public Run(int state) {
        this.state = state;
    }
    public void process(){
        // if RUNNING / STOP
    }
}

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

这种情况怎么办呢?

class Run {
    public static final int RUNNING = 1;
    public static final int STOP = 2;
    protected int state;
    //私有构造方法外部无法调用
    private Run(int state) {
        this.state = state;
    }
    public static Run running(){
        return new Run(RUNNING);
    }
    public static Run stop(){
        return new Run(STOP);
    }
    public void process(){
        // if RUNNING / STOP
    }
}

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

3. 总结

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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343