Java code optimization - static factory method and public constructor

Usually, we use new to create an object. This should be the easiest way. But an excellent programmer needs to consider specific application scenarios and performance issues in order to write excellent code. So let's start with creating objects and learn how to create objects?
This article compares static factory methods and public constructors, analyzes their advantages and disadvantages, and provides recommended methods for creating objects in different scenarios.

Two ways to create objects:
Method 1: Use the class public constructor.
Method 2: Use the static factory method of the class to return an instance.

What is a static factory method?

The static factory method (static factory methods) is a static method modified by static to return an instance of the class.

Here is a simple example of a static factory method (taken from JDK 1.7 java.lang.Boolean).

public final class Boolean implements java.io.Serializable,
       Comparable<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);
   }
}

If you need to obtain a Boolean object, the conventional method is new Boolean(true), but you can also use Boolean.valueOf(true) as shown in the figure above, which is the static factory method.

The difference between a static factory method and a public constructor:
1: The name of the constructor must be the same as the class name. The advantage of this feature is that it conforms to the Java language specification. The disadvantage is that all overloaded constructors of the class have the same name, and each overloaded method cannot be distinguished from the name, which is easy to cause confusion. The method name of the static factory method can be arbitrary. The advantage of this feature is that it can improve the readability of the program code, and the information related to the instance can be reflected in the method name. Different factory methods have different names, so we can easily remember what method names can construct what kind of objects. Regarding this point, one of the most convincing examples in JDK is java
. Create a new object. Whether a static factory method will create a new object each time it is called depends entirely on the implementation of the method. What we call the static factory method may return a cached object instead of a new object. This can reduce the creation of new objects, thereby improving performance, the aforementioned Boolean is an example. This is especially useful for objects of immutable classes, because of the immutability of objects, only one instance of the object needs to be implemented. The packaging class Integer takes advantage of this idea, and the static factory function in Integer is as follows:

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

The above code creates a cache for the int with a high probability of occurrence, so that each time it only needs to return the object in the cache instead of creating a new object.
The singleton pattern is a way to use a static factory method to obtain an object instance. Make sure there is only one object instance of the class.
3: The new statement can only create an instance of the current class, while the static factory method can return an instance of a subclass of the current class. This feature makes static factory methods much more scalable than constructors. The most typical one in JDK should be java.util.EnumSet. EnumSet itself is abstract, we cannot directly call its constructor. However, we can call its static method noneOf to create an object. RegularEnumSet/JumboEnumSet inherits from EnumSet, and noneOf returns the appropriate object according to the parameters.

public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
    implements Cloneable, java.io.Serializable {
    
    

    EnumSet(Class<E>elementType, Enum[] universe) {
    
    
    }

    public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
    
    
        if (universe.length <= 64)
            return new RegularEnumSet<>(elementType, universe);
        else
            return new JumboEnumSet<>(elementType, universe);
    }
}

Disadvantages of static factory methods:

  1. If a class can only obtain instances through static factory methods, then the constructor of the class cannot be shared or protected, then the class will not have subclasses, that is, the class cannot be inherited. In the singleton mode, the constructor must first be privatized.
     2. Static factory methods are indistinguishable from other static methods by name. It is recommended to follow certain rules when naming static factory methods.

valueOf — return the same object as the parameter, usually used for type conversion, such as Intger.valueOf(int i)
of — similar to valueOf.
getInstance — returns the corresponding object according to the parameter, which may be an object cached in the object pool. For singletons, we use getInstance with no parameters, and always return the same object
newInstance — the same as getInstance, but each call of this method returns a new object.
getType — Similar to getInstance, but the difference is that the object returned by this method is a different class.
newType — Similar to getType, but returns a new object each time.

The main feature of the static factory method is that it does not necessarily create a new object each time it is called. Taking advantage of this feature, static factory methods can be used to create instances of the following classes.

<1>Singleton class: only one instance. Once an instance is created, its attribute values ​​will not be changed.

<2> Enumeration class: a class with a limited number of instances.

<3> Classes with instance caches: Classes that can temporarily store created instances in the cache.

Guess you like

Origin blog.csdn.net/weixin_45817985/article/details/130720777