简体   繁体   中英

Immutable class using static factories

I'm studying Effective Java by Joshua Bloch, where he explains about different ways of achieving immutable class. To prevent subclassing, one way is to use final . The more sophisticated way for it is to make constructor private, thus preventing outside access, and using static factories for object creation.

However, I don't understand this statement:

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);
    }
}

It is most flexible because it allows the use of multiple package-private implementation classes.

I understand that it's not possible for an outside client to subclass it in absence of a public/protected constructor, but do not understand what is being conveyed by the term 'multiple package private implementation classes'.

NOTE: This is Item 15 (Minimize mutability) in Effective Java.

As far as I remember Joshua then talks about EnumSet (but I do not remember context where he mentions it).

EnumSet is abstract and also has static methods of , noneOf , etc. There are two classes extending EnumSet : JumboEnumSet and RegularEnumSet .

You cannot use them directly because they are package-private (no public keyword):

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

java.util package only can use them directly (if we do not speak about reflection or some other techinques).

You simply use static methods of EnumSet and it returns some subclass of EnumSet you should not be aware of.

Take a look at the noneOf method implementation:

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);
}

Here is the multiple package-private implementations

The only way a class cannot be subclassed is if the class is marked as final . Since this class is not final , then it can be subclassed , like this:

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);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM