Static Initializers and Lazy Instantiation UPAccess
程序员文章站
2024-02-27 22:50:45
...
Why use Lazy Instantiation when static initialization is more efficient? Well, there are pros and cons to both, and there is no firm answer.
The Singleton article gave one solution for implementing global variables, but it wasn't the only solution. Java does, in fact, have global variables of a sort, but they're called class variables. Here is an example:
"The most important reason for using Lazy Instantiation is keeping resources under control. "
In Listing 1, the static keyword is used to indicate that this particular variable, namely object1, is a class variable rather than an instance variable. This means that there will be only one copy of the variable for the class rather than one for each instance of the class. The code segment in Listing 1 not only creates the variable, it also contains a static initializer that gives the object a value. This static initialization occurs automatically when the class containing the variable is first accessed.
Here, first accessed is defined to be the first time one of the following events occurs:
An instance of the class is created via a constructor.
A static method that is defined in the class (not inherited) is called.
A static variable that is declared in the class (not inherited) is assigned or otherwise accessed. This does not include the static initializer, which occurs at compile time.
The process of Lazy Instantiation, on the other hand, doesn't automatically allocate variables. It enables the creation of objects to be put off until they are actually needed. Instead of being created when the program first starts, the creation of variables managed via Lazy Instantiation is deferred until they are actually required.
Which is better? Lets start off with some examples.
Here is an example of static initialization:
In Listing 2,object1 is created and its value is initialized when the class
MyClass is first accessed. After some period of time,object1 will be used via the
doProcess() method.
Here is a similar code segment making use of Lazy Instantiation.
The code in Listing 3 performs the same function as in Listing 2 except that the
object1 variable is being managed via Lazy Instantiation. When MyClass is created, nothing is done with object1 other than implicitly setting its reference to null. The doProcess() method makes use of object1 and checks to see if it exists before using it. If it does not exist, an instance is created and then used.
Now back to the big question: Which is better?
Different Purposes
When it comes to speed, the static version wins. Static methods are quicker than normal ones, as there is no code execution overhead. Classes implementing Lazy Instantiation contain management code that needs to be executed whenever access to a variable is required. In Listing 3, overhead is incurred every time object 1 is accessed, because it first needs to be checked for a null value.
For ease of programming, static wins again. Only a single line of code is required to implement a variable with a static initializer. As mentioned above, Lazy Instantiation requires that an object be checked for a null value every time it is accessed. Also, multithreaded applications would require use of the double-checked locking pattern, which results in additional code. (See previous article on Singletons for more information on this.)
Okay, so there are several reasons for using a static initializer, as my readers have mentioned. However, there are several good reasons to use Lazy Instantiation instead.
The first reason for Lazy Instantiation concerns the initialization of the managed object's value. For a static initializer, the initial value is determined at compile time. When the developer puts to code the line that creates the object, he or she also determines what the initial value is going to be. While this is fine for many uses, there are times when it just isn't good enough. Lazy Instantiation, however, initializes the value of an object when the object is created. Since the object is being created at runtime, there is much more data available which can be used to calculate an appropriate initial value. One example of this would be the placing of a user name and id in a session variable.
Secondly, items that are static cannot be used to implement an interface. Interfaces in Java are powerful programming constructs that allow classes to inherit method definitions. Static objects suffer a loss of a great deal of programming power by not being able to implement interfaces.
The most important reason of all for using Lazy Instantiation, however, is that of keeping resources under control. Static objects are always created, whether they are needed or not. If the object is never used, then space is wasted holding the object and time is wasted creating it. Objects managed by Lazy Instantiation will only be created if they are needed and do not suffer these problems. This is especially important if the resources used are valuable, such as a database connection. Why tie up a database connection if it is never going to be used?
Also, since static objects are created during the initialization of a Java program, a lot of processing needs to be done before the program can actually begin. Software built with Lazy Instantiation defers the creation of objects and thus starts up a lot faster. This makes the Java program appear more agile and responsive, a definite bonus if you are trying to sell the software to a client.
Summary
The pros and cons of static initializers versus Lazy Instantiation must be weighed to determine which is best for a given use. Both are powerful, and both are examples of good programming, but they serve different purposes.
The Singleton article gave one solution for implementing global variables, but it wasn't the only solution. Java does, in fact, have global variables of a sort, but they're called class variables. Here is an example:
"The most important reason for using Lazy Instantiation is keeping resources under control. "
- Listing 1
static MyObject object1 = new MyObject()
In Listing 1, the static keyword is used to indicate that this particular variable, namely object1, is a class variable rather than an instance variable. This means that there will be only one copy of the variable for the class rather than one for each instance of the class. The code segment in Listing 1 not only creates the variable, it also contains a static initializer that gives the object a value. This static initialization occurs automatically when the class containing the variable is first accessed.
Here, first accessed is defined to be the first time one of the following events occurs:
An instance of the class is created via a constructor.
A static method that is defined in the class (not inherited) is called.
A static variable that is declared in the class (not inherited) is assigned or otherwise accessed. This does not include the static initializer, which occurs at compile time.
The process of Lazy Instantiation, on the other hand, doesn't automatically allocate variables. It enables the creation of objects to be put off until they are actually needed. Instead of being created when the program first starts, the creation of variables managed via Lazy Instantiation is deferred until they are actually required.
Which is better? Lets start off with some examples.
Here is an example of static initialization:
- Listing 2
public class MyClass { static MyObject object1 = new MyObject(); void doProcess() { object1.process(); } }
In Listing 2,object1 is created and its value is initialized when the class
MyClass is first accessed. After some period of time,object1 will be used via the
doProcess() method.
Here is a similar code segment making use of Lazy Instantiation.
- Listing 3
public class MyClass { MyObject object1; void doProcess() { If (object1 == null) object1 = new MyObject(); object1.process(); } }
The code in Listing 3 performs the same function as in Listing 2 except that the
object1 variable is being managed via Lazy Instantiation. When MyClass is created, nothing is done with object1 other than implicitly setting its reference to null. The doProcess() method makes use of object1 and checks to see if it exists before using it. If it does not exist, an instance is created and then used.
Now back to the big question: Which is better?
Different Purposes
When it comes to speed, the static version wins. Static methods are quicker than normal ones, as there is no code execution overhead. Classes implementing Lazy Instantiation contain management code that needs to be executed whenever access to a variable is required. In Listing 3, overhead is incurred every time object 1 is accessed, because it first needs to be checked for a null value.
For ease of programming, static wins again. Only a single line of code is required to implement a variable with a static initializer. As mentioned above, Lazy Instantiation requires that an object be checked for a null value every time it is accessed. Also, multithreaded applications would require use of the double-checked locking pattern, which results in additional code. (See previous article on Singletons for more information on this.)
Okay, so there are several reasons for using a static initializer, as my readers have mentioned. However, there are several good reasons to use Lazy Instantiation instead.
The first reason for Lazy Instantiation concerns the initialization of the managed object's value. For a static initializer, the initial value is determined at compile time. When the developer puts to code the line that creates the object, he or she also determines what the initial value is going to be. While this is fine for many uses, there are times when it just isn't good enough. Lazy Instantiation, however, initializes the value of an object when the object is created. Since the object is being created at runtime, there is much more data available which can be used to calculate an appropriate initial value. One example of this would be the placing of a user name and id in a session variable.
Secondly, items that are static cannot be used to implement an interface. Interfaces in Java are powerful programming constructs that allow classes to inherit method definitions. Static objects suffer a loss of a great deal of programming power by not being able to implement interfaces.
The most important reason of all for using Lazy Instantiation, however, is that of keeping resources under control. Static objects are always created, whether they are needed or not. If the object is never used, then space is wasted holding the object and time is wasted creating it. Objects managed by Lazy Instantiation will only be created if they are needed and do not suffer these problems. This is especially important if the resources used are valuable, such as a database connection. Why tie up a database connection if it is never going to be used?
Also, since static objects are created during the initialization of a Java program, a lot of processing needs to be done before the program can actually begin. Software built with Lazy Instantiation defers the creation of objects and thus starts up a lot faster. This makes the Java program appear more agile and responsive, a definite bonus if you are trying to sell the software to a client.
Summary
The pros and cons of static initializers versus Lazy Instantiation must be weighed to determine which is best for a given use. Both are powerful, and both are examples of good programming, but they serve different purposes.