使用静态工厂的不可变 class

Immutable class using static factories

我正在学习 Joshua Bloch 的 Effective Java,他在其中解释了实现不可变 class 的不同方法。要防止 subclassing,一种方法是使用 final。更复杂的方法是将构造函数设为私有,从而防止外部访问,并使用静态工厂创建对象。

但是,我不明白这个说法:

public class Complex {
    private final double re;
    private final double im;

    private Complex(double re, double im) {
        this.re = re;
        this.im = im;
    }

    public static Complex valueOf(double re, double im) {
        return new Complex(re, im);
    }
}

它最灵活,因为它允许使用多个 package-private 实现 classes.

我知道在没有 public/protected 构造函数的情况下,外部客户不可能继承 class 它,但不明白 'multiple package private implementation classes' 这个词所表达的意思.

注意:这是 Effective Java 中的第 15 项(最小化可变性)。

class 不能被子class 的唯一方法是 class 被标记为 final。既然这个class不是final,那么可以subclassed,像这样:

public class Complex {

    private final double re;
    private final double im;

    private Complex(double re, double im) {
        this.re = re;
        this.im = im;
    }

    //methods...

    static class SubComplex1 extends Complex {

        private SubComplex1(double re, double im, double x) {
            super(re, im);
            //more elements...
        }
        //you can define/override methods here
    }

    public static Complex valueOf(double re, double im, double x) {
        return new SubComplex1(re, im, x);
    }
}

据我所知,约书亚随后谈到了 EnumSet(但我不记得他提到它的上下文)。

EnumSet是抽象的,也有静态方法of, noneOf等。 有两个类扩展EnumSetJumboEnumSetRegularEnumSet

你不能直接使用它们,因为它们是包私有的(没有 public 关键字):

class RegularEnumSet<E extends Enum<E>> extends EnumSet<E>
class JumboEnumSet<E extends Enum<E>> extends EnumSet<E>

java.util 包只能直接使用它们(如果我们不谈论反射或其他一些技术)。

您只需使用 EnumSet 的静态方法,它 returns 您不应该知道的 EnumSet 的某些子类。

看看noneOf方法的实现:

public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
    Enum<?>[] universe = getUniverse(elementType);
    if (universe == null)
        throw new ClassCastException(elementType + " not an enum");

    if (universe.length <= 64)
        return new RegularEnumSet<>(elementType, universe);
    else
        return new JumboEnumSet<>(elementType, universe);
}

这是多个包私有实现