Effective Item-Consider a static factory method instead of a constructor we have two common ways to get an instance of a class:
- Public constructors
- Provides static factory methods (static Factory method)
The static factory method has the following advantages over the public constructor.
Advantage 1. The name of the static factory method, and therefore more accurately describes the returned instance than the constructor.
For example Biginteger.probableprime method:
public static BigInteger probablePrime(int bitLength, Random rnd) { if (bitLength < 2) throw new ArithmeticException("bitLength < 2"); // The cutoff of 95 was chosen empirically for best performance return (bitLength < SMALL_PRIME_THRESHOLD ? smallPrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd) : largePrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd));}
By the way also post the Largeprime method of its invocation:
private static BigInteger largePrime(int bitLength, int certainty, Random rnd) { BigInteger p; p = new BigInteger(bitLength, rnd).setBit(bitLength-1); p.mag[p.mag.length-1] &= 0xfffffffe; // Use a sieve length likely to contain the next prime number int searchLen = (bitLength / 20) * 64; BitSieve searchSieve = new BitSieve(p, searchLen); BigInteger candidate = searchSieve.retrieve(p, certainty, rnd); while ((candidate == null) || (candidate.bitLength() != bitLength)) { p = p.add(BigInteger.valueOf(2*searchLen)); if (p.bitLength() != bitLength) p = new BigInteger(bitLength, rnd).setBit(bitLength-1); p.mag[p.mag.length-1] &= 0xfffffffe; searchSieve = new BitSieve(p, searchLen); candidate = searchSieve.retrieve(p, certainty, rnd); } return candidate;}
Although Smallprime and Largeprime end up returning instances through the public constructor.
But if you just use a constructor overload to express the characteristics of this instance, it's hard to remember when you should call any constructors.
and providing a name to describe the instance is more intuitive.
Advantage 2. The static factory method does not have to create a new object each time, we can control the instance.
This allows us to cache the created instances and reuse them, especially if the object is created at a higher cost.
such as boolean.valueof:
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);}
Advantage 3. A static factory method can return a subtype object of the original return type.
This can reflect the flexibility of the static factory approach,
Take Enumset as an example:
/** * Creates an empty enum set with the specified element type. * * @param elementType the class object of the element type for this enum * set * @throws NullPointerException if <tt>elementType</tt> is null */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);}
Regularenumset and Jumboenumset are subclasses of Enumset, and none of them provide a public constructor.
Advantage 4. Static factory methods are more concise when creating parameterized (generic) instances.
As an example:
public static <K, V> HashMap<K, V> newInstance() { return new HashMap<K, V>();}
When you create an instance, you can:
Map<String,List<Integer>> n = newInstance();
Instead of
Map<String,List<Integer>> m = new HashMap<String,List<Integer>>();
It makes no sense to start from Java7, in fact Josh Bloch also mentions this in the book--java later, this type deduction is performed in constructors and method calls.
Talk about the drawbacks of the static factory approach.
- Classes cannot be overridden if they do not contain a public or protected constructor.
So the static factory method mentioned above can return the subtype object of the original return type. is not entirely correct.
Although we can solve this problem through a composite approach (composition), the two classes are not is-a relationships.
- The nature of the static factory approach is still a static method, and he does not have a particular standard.
We cannot specifically identify a static factory method in the API documentation (perhaps by adding a standard annotation?).
When I want to find a way to instantiate a class from the API, it is still not intuitive relative to the constructor.
Although there is no special standard, we can make up a little bit with the standard naming.
such as Valueof,getinstance,newinstance,newtype, etc...
Effective Java-consider replacing constructors with static factory methods