All
chained
constructors
are automatically called when creating an object with
new
. Chaining more constructors for a particular
object causes extra
overhead at
object creation, as does initializing instance variables more than
once
.
Be aware of the default values that Java initializes variables to:
null
for objects0
for integer types of all lengths (byte
,char
,short
,int
,long
)0.0
for float types (float
anddouble
)false
forboolean
s
There is no need to reinitialize these values in the constructor (although an optimizing compiler should be able to eliminate the extra redundant statement). Generalizing this point: if you can identify that the creation of a particular object is a bottleneck, either because it takes too long or because a great many of those objects are being created, you should check the constructor hierarchy to eliminate any multiple initializations to instance variables.
You can avoid constructors by unmarshalling objects from a serialized
stream, because deserialization does not use constructors. However,
serializing and deserializing objects is a CPU-intensive procedure
and is unlikely to speed up your application. There is another way to
avoid constructors when creating objects, namely by creating a
clone( )
of an object. You can create new
instances of classes that implement the
Cloneable
interface using the clone()
method. These new instances do not call any class
constructor, thus allowing you to avoid the constructor
initializations.
Cloning does not
save a lot of time because the main overhead in creating an object is
in the creation, not the initialization. However, when there are
extensive initializations or many objects generated from a class with
some significant initialization, this technique can help.
If you have followed the factory design pattern,[32] it is relatively simple to reimplement the original factory method to use a clone. For example, the original factory method can be defined similar to:
public static Something getNewSomething( ) { return new Something( ); }
The replaced implementation that uses cloning looks like:
private static Something MASTER_Something = new Something( ); public static Something getNewSomething( ) { return (Something) MASTER_Something.clone( ); }
If you have not followed the factory design pattern, you may need to track down all calls that create a new instance of the relevant class and replace those calls. Note that the cloned object is still initialized, but the initialization is not the constructor initialization. Instead, the initialization consists of assigning exactly once to each instance variable of the new (cloned) object, using the instance variables of the object being cloned.
Java arrays all support cloning. This allows you to manage a similar trick when it comes to initializing arrays. But first let’s see why you would want to clone an array for performance reasons.
When you create an array in code, using the curly braces to assign a newly created array to an array variable like this:
int[] array1 = {1,2,3,4,5,6,7,8,9};
you might imagine that the
compiler creates
an array in the compiled file, leaving a nice structure to be pulled
in to memory.
In fact, this is not what
happens. The array is still created at runtime, with all the elements
initialized then. Because of this, you should specify arrays just
once, probably as a static
, and assign that array
as required. In most cases this is enough, and there is nothing
further to improve on because the array is created just once. But
sometimes you have a routine for which you want to create a new array
each time you execute it. In this case, the complexity of the array
determines how efficient the array creation is. If the array is quite
complex, it is faster to hold a reference copy and clone that
reference than it is to create a new array. For instance, the array
example shown previously as array1
is simple and
therefore faster to create, as shown in that example. But the
following more complex array, array2
, is faster to
create as a cloned array:
static int[] Ref_array1 = {1,2,3,4,5,6,7,8,9}; static int[][] Ref_array2 = {{1,2},{3,4},{5,6},{7,8}}; int[] array1 = {1,2,3,4,5,6,7,8,9}; //faster than cloning int[] array1 = (int[]) Ref_array1.clone( ); //slower than initializing int[][] array2 = {{1,2},{3,4},{5,6},{7,8}}; //slower than cloning int[][] array2 = (int[][]) Ref_array2.clone( );//faster than initializing
[32] The factory design
pattern recommends that object creation be centralized in a
particular factory method. So instead of
directly calling new
Something()
in the code to create an instance of the
Something
class, you call a method such as
SomethingFactory.getNewSomething( )
, which creates
and returns a new instance of the Something
class.
This is actually detrimental for performance, as there is the
overhead of an extra method call for every object creation, but the
pattern does provide more flexibility when it comes to tuning. My
inclination is to use the factory pattern. If you identify a
particular factory method as a bottleneck when performance-tuning,
you can relatively easily inline that factory method using a
preprocessor.
Get Java Performance Tuning now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.