高度な開発には効率的なJavaが必要です

高度な開発少なくともいくつかの高度なスキルですね。では、これらの高度なスキルはどこから来るのでしょうか?

最初の方法は本を読むことでなければなりません、何ですか?そんなに時間がないの?

幸いなことに、私はここで忙しく、あなたは速読モードをオンにして、「効率的なJava」シリーズを学ぶために私に従ってきました。

最初に立ち寄るのはここです:静的ファクトリメソッド

1.静的ファクトリメソッドとは何ですか?

  • 静的ファクトリメソッドは、オブジェクトを作成する方法です。

  • ここでの静的ファクトリメソッドは、デザインパターンのファクトリパターンではありません。

  • 静的ファクトリメソッドは、クラスの通常の静的メソッドであり、その最終的な効果はコンストラクターの効果と同等です。

そうは言っても、理解するための例を挙げましょう。

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

上記の例のvalueOfandgetInstance静的

2.静的ファクトリメソッドの利点

では、なぜ静的ファクトリメソッドにコンストラクターではなくオブジェクトを作成するように勧めるのでしょうか。

その理由は次のとおりです。

  • 静的ファクトリメソッドには名前がありますが、コンストラクタには名前がありません

  • 静的ファクトリメソッドが呼び出されるたびにオブジェクトを作成する必要はありません

  • 現在のクラスの任意のサブタイプオブジェクトを返すことができます

  • ユーザーエラーの可能性を減らす

これらの利点を1つずつ見ていきましょう。

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) {}
复制代码

非常に多くの異なるパラメータの構築方法を見て、日付がわからない場合、混乱しますか?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. 总结

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

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

おすすめ

転載: juejin.im/post/7077750408667463717