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.?!
CodePudding user response:
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.
CodePudding user response:
Your booleanWrapped variable does not reference a newly created object. It references the static Boolean.TRUE
created the first time the Boolean class loads. All calls to Boolean.valueOf(true)
simply reuse that single object.
CodePudding user response:
The method valueOf
never creates a new object (there is no new
expression and no other method call that could transitively call a constructor). The method simply returns one of 2 static fields (Boolean.TRUE
or Boolean.FALSE
). These fields already exist and the objects they reference were already created (outside and before the method valueOf
).
Obviously, the objects have to be created somewhere; but they are not created in the method valueOf
.
And "returning an object" != "creating an object".
public static Object demo() {
final Object obj = new Object(); // `new` creates the object
return obj; // `return` returns the object, it does not create a new one
}
CodePudding user response:
Both Boolean.TRUE
and Boolean.FALSE
are pre-existing static
members defined by the Boolean class.
One important concept to not overlook in understanding the benefit of static factory methods over traditional constructors is why Josh Bloch specifies that immutable classes can be cached or pre-constructed. The point isn't really about whether or not a single object is constructed at the time that static factory method is called the first time, but rather how it can conserve resources when used multiple times. The savings is all about returning a pre-existing immutable instance rather than constructing a new one.