Search code examples
javastatic-methodsfactory-methodeffective-java

Joshua Bloch Item #1 Static Factory Methods Instead of Constructors - Object creation


Source of Question

I was wondering about the following advantage of Static Factory Methods described by Joshua Blochs "Effective Java", 3rd edition in item #1:

A second advantage of static factory methods is that, unlike constructors, they are not required to create a new object each time they’re invoked. This allows immutable classes (Item 15) to use preconstructed instances, or to cache instances as they’re constructed, and dispense them repeatedly to avoid creating unnecessary duplicate objects. The Boolean.valueOf(boolean) method illustrates this technique: it never creates an object.

See extract here.

Question

What got my attention was the last line about valueOf(boolean) not creating an object. According to the book

public static Boolean valueOf(boolean b) {
    return b ? Boolean.TRUE : Boolean.FALSE;
}

and the Javadoc

public static Boolean valueOf(boolean b)

Returns a Boolean instance representing the specified boolean value. If the specified boolean value is true, this method returns Boolean.TRUE; if it is false, this method returns Boolean.FALSE. If a new Boolean instance is not required, this method should generally be used in preference to the constructor Boolean(boolean), as this method is likely to yield significantly better space and time performance.

So from my understanding and the Javadoc ("Returns a Boolean instance...") the static method returns indeed a Boolean and therefore an object - as it is literally the return type. In the following case:

public class MyClass {
    public static void main(String args[]) {
        Boolean booleanWrapped = Boolean.valueOf(true);
        System.out.println(booleanWrapped);
    }
}

booleanWrapped is my object I can use e.g. like in the prinln() statement.

So what am I missing here if Joshua states

The Boolean.valueOf(boolean) [...] never creates an object

I'm aware of a similar question with an existing answer but it doesn't seem to fully answer my question as in my example above there isn't an "pre-existing" instance.?!


Solution

  • As of Java 9, Boolean has a deprecated constructor. But this still demonstrates the difference.

    So Boolean b1 = new Boolean(true). creates a new instance and stores it in b1.

    Boolean b1 = new Boolean(true);
    Boolean b2 = new Boolean(true);
    System.out.println(System.identityHashCode(b1));
    System.out.println(System.identityHashCode(b2));
    

    Two different identity hashcodes imply different objects

    804564176
    1421795058
    

    Now use the existing static instance.

    Boolean b1 = Boolean.TRUE;
    Boolean b2 = Boolean.TRUE;
    System.out.println(System.identityHashCode(b1));
    System.out.println(System.identityHashCode(b2));
    

    Sharing the same object - same hashcode.

    804564176
    804564176
    

    Within the Boolean class you have the following:

    public static final Boolean TRUE = new Boolean(true);
    public static final Boolean FALSE = new Boolean(false);
    

    So they are created when the class is loaded.