The constant object has many features that can easily use their features, including uncompected synchronization needs and unnecessary data corruption can be freely shared and cache object references. Although invariance may not be meaningful for all classes, at least some classes in most programs will benefit from immobilization. In Java theory and practice this month, Brian Goetz illustrates some guidelines for some of the incomplete strengths and constructors. Please come with
forum
Share your experience with the author and other readers. (You can also access the forum to access the Forum on the top of the article or the bottom of the article.)
The constant object refers to an object that cannot be changed outside of its external visible state after instantiation. String, Integer, and BigDecimill classes in the Java class library are examples of constant objects - they represent a single value that cannot be changed during the life of the object.
If the length of the invariance is not used correctly, they will greatly simplify programming. Because they can only be in a state, they will never fall into the inconsistent state as long as they are correctly constructed. You don't have to copy or clone the constant object, you can freely share and cache them for them; you can cache their fields or their methods, without worrying, will not turn into failure or with objects Other states are inconsistent. The invariant class usually produces the best mapping key. Moreover, they are currently a thread safe, so they don't have to synchronize their access between threads.
Free cache because the value of the constant object does not change the risk, so you can freely cache the reference to them, and you can definitely reference the same value. Similarly, because their characteristics cannot be changed, you can cache their fields and their methods.
If the object is variable, you must pay attention when storing the reference. Consider the code in Listing 1, which arrays two tasks performed by the scheduler. The purpose is: Start the first task now, and start the second task on one day.
Listing 1. Potential problem with variable DATE objects
Date D = new date ();
Scheduler.scheduletask (Task1, D);
D.SetTime (D.getTime () one_day);
Scheduler.scheduletask (Task2, D);
Since Date is variable, the Scheduletask method must carefully use preventive measures to copy the date parameters (possibly via clone ()) to its internal data structure. Otherwise, Task1 and Task2 may be implemented tomorrow, which is not expected. Worse, the internal data structure used by the task scheduler will become a corruption. When writing a method like Scheduletask (), it is extremely easy to forget to copy the date parameters with prevention measures. If you forget to do this, you have made a difficult to capture, this error will not be immediately displayed, and when it exposes people to spend longer, it will capture. This kind of error cannot occur in the constant DATE class.
Inherent thread safety Most thread security issues occur when multiple threads are trying to modify the status of an object (write-write conflict), or when a thread is trying to access an object, and another thread is Modify it (read - write conflict). To prevent such conflicts, you must synchronize access to shared objects so that other threads cannot access them when the object is inconsistent. It will be difficult to do this correctly, you need a lot of documentation to ensure proper expansion programs, and you may also have adverse consequences. As long as the constant object is correct (this means that it is not allowed to escape from the constructor), they eliminate the requirements of synchronous access, because they cannot change their status, so that there is impossible to write - write conflicts or read - Write conflicts.
You can share references to constant objects without synchronization, which can greatly simplify the process of writing concurrency programs and reduce the number of potential errors that can exist in programs. In front of the malicious operation, it is safe to treat the object as a parameter. The state of the object should not change the status of the object, unless the documentation is clearly described, or actually these methods have the ownership of the object. When we pass an object to a normal method, it usually does not want to return when the object returns. However, when using variable objects, it will be like this. If java.awt.point passes to a method such as Component.SetLocation (), it does not block setLocation from modifying the location of our incoming Point, and does not block setLocation stores the reference to this point and later in another method. Change it in it. (Of course, Component does not do this, because it is not illegal, but not all classes are so polite.) Now, the state of Point has changed in the case of we don't know, and its results have potential danger - the point is actually When another location, we still think that it is in the original position. However, if Point is constant, this malicious code cannot modify our program in this chaotic and dangerous approach.
A good key constant object produces the best HashMap or Hashset key. Some variable objects changes their HashCode () values (such as the StringHolder sample class in Listing 2) based on their status. If this variable object is used as a Hashset button, then the object changes its status, then the HashSet implementation causes confusion - if the enumeration collection, the object will still appear, but if you use the Contains () query collection, it may does not appear. There is no need to say, this will cause certain confusion. Note The code in Listing 2 in this situation will print "false", "1", and "MOO".
Listing 2. Variable STRINGHOLDER class, not suitable for use
Public class stringholder {
PRIVATE STRING;
Public StringHolder (string s) {
THIS.STRING = S;
}
Public string getString () {
Return string;
}
Public void setstring (string string) {
THIS.STRING = String;
}
Public Boolean Equals (Object O) {
IF (this == O)
Return True;
Else IF (o == Null ||! (o instanceof stringholder))
Return False;
Else {
Final StringHolder Other = (STRINGHOLDER) O;
IF (String == Null)
Return (other.string == null);
Else
Return string.equals (other.string);
}
}
Public Int hashcode () {
Return (String! = NULL? String.hashcode (): 0);
}
Public string toString () {
Return string;
}
...
StringHolder sh = New StringHolder ("Blert");
Hashset h = new hashset ();
H.Add (sh);
Sh.setString ("MOO"); System.out.Println (H.Contains (SH));
System.out.println (H.Size ());
System.out.println (H.Iiterator (). Next ());
}
When the invariant category is used to optimize the value of the abstract data type (such as numbers, enumeration types or colors). Basic digital classes in the Java class library (such as Integer, Long and Float) are constant, other standard digital types (such as Biginteger and BigDecimal) are also constant. Indicates that the plurality or accuracy arbitrary allegitudes will be more suitable for invariance. Even abstract types of many discrete values (such as vector or matrices) are also very suitable for unrecognizable classes, depending on your application.
Flyweight mode does not change the Flyweight mode, which utilizes sharing to effectively represent a large number of fine particle size objects. For example, you may want to use an object to represent each character or an image in the word processing document, but the naive implementation of this policy will produce highly amazing spending of memory usage and memory management overhead. The Flyweight mode uses a factory method to assign a reference to the unchanged fine particle size object, and use only one object instance to use the shared reduction target number by passing only the alphabet "A". For more information on Flyweight mode, please refer to Classic Books Design Patterns (gamma waiting; see Resources).
Another nice example of the invariant in the Java class library is java.awt.color. In some color representations (such as RGB, HSB or CMYK), the color is usually represented as a set of ordered digital values, but a color is used as a specific value in the color space, not a group of orderly. The value of independent addresses is more meaningful, so it is reasonable to implement Color as an invariant.
If the object to be represented is a plurality of basic values (such as point, vector, matrix or RGB color), is it represented by a variable object or a constant object? The answer is ... to see the situation. How do you use them? They are mainly used to represent multi-dimensional values (such as pixel color), or only use as a set of related characteristic sets (such as the height and width of the window) of other objects? How long does these features change this time? If you change them, do all component values have their own meaning in the application?
Event is another good example for implementation of the invariant class. The event's life is shorter, and often consumes in threads other than their threads, so that they become constant. Most AWT event classes are not implemented as a strict invariant class, but can have small modifications. Similarly, in a system using a certain form of messaging to communicate between components, it may be sensible to make the message object unchanged.
Criteria for writing invariance is easy to write. If the following points are true, then the class is constant:
Its Field is Final This class declares that Final does not allow this to reference to any fields included in the constructor any field containing variable objects (such as arrays, collections, or similar data:
It is privately from being returned or not otherwise publication to the calling program is the state of the referenced object without changing the unique reference configuration of the object they reference.
The last set of requirements seems to be quite complex, but it basically means that if you want to store a reference to an array or other variable object, you must ensure that your class has exclusive access to the variable object (because otherwise, other classes Can change its status) and you do not modify its status after constructing. This complexity is necessary for allowing the invariant object to store the reference to the array, because the Java language has no way to enforce the elements of the final array. Note: If you initialize an array reference or other variable field from the parameter passed to the constructor, you must use preventive measures to copy the arguments provided by the calling program or you cannot ensure that other information with exclusive access is copied to an array. Otherwise, the calling program modifies the status of the array after calling the constructor. Listing 3 shows the correct way to write the configuration function of the constant objects of the array provided by the stored call program (and error). Listing 3. Correct and error method for coding constant object
Class ImmutableArrayHolder {
PRIVATE FINAL INT [].
// Right Way to Write a Constructor - Copy THE ARRAY
Public ImmutableArrayHolder (int [] AnaRray) {
THIS.THEARRAY = (int []) Anarray.clone ();
}
// WRONG WAY TO WRITE A Constructor - Copy The Reference
// the caller could change the array after the call to the constructor
Public ImmutableArrayHolder (int [] AnaRray) {
THIS.THEARRAY = AnArray;
}
// Right Way to Write An Accessor - Don't Expose The Array Reference
Public int GetArrayLength () {return thearray.length}
Public int GetArray (int N) {return thearray [n];}
// Right Way to Write an Accessor - Use Clone ()
Public int [] getArray () {return (int []) THEARRAY.CLONE ();
// WRONG WAY to WRITE AN Accessor - Expose The Array Reference
// a caller could get the array reason and then change the contents
Public int [] getArray () {return thealay}
}
With some other work, you can write non-final fields (for example, String standard implementation using the inert calculation of the HashCode value), which may be better than the strict final class. If the class represents the value of an abstract type (such as digital type or color), you will also want to implement a HashCode () and equals () method so that the object will work well as a key in the HashMap or Hashset. To keep thread security, this reference is not allowed to escape from constructor.
Occasionally, some data items have kept constant in the program life phase, and some will change frequently. Constant data is clearly compliant, and objects that are complex and frequently changed are often unaffitable. So sometimes change, but the change is not too frequent data? What is the way to make the data that sometimes changed the uncultivation convenience and the length of thread safety? The CopyonWriteArraylist class in the util.concurrent package uses the ability to use invariance and a good example that occasionally modified. It is best suited to support class (such as user interface components) for event listeners. Although the list of event listeners can be changed, it usually changes much more frequently more than the generation of events.
In addition to the list of changes, CopyonWriteArrayList does not change the basic array, but create a new array and discard the old array, its behavior is very similar to the ArrayList class. This means that when the calling program obtains an iterator (the iterator saves the basic array reference), the array referenced by the iterator is actually unchanged, so that there is no need to synchronize or violate the risk of modification. This eliminates the need to synchronize the list before traversing or in the traversal, which is very troublesome, easy to make mistakes, and completely deteriorate performance. If the traversal is more frequent than insertion or removal (this is common in some cases), CopyonWriteArrayList will provide better performance and more convenient access.
End language Use constant objects to be much easier than using variable objects. They can only be in a state, so they are always consistent, they are originally threaded, which can be freely shared. Using constant objects can completely eliminate many programming errors that are easy to detect, such as unable to simultaneously access or unable to clone the array or objects before the reference to the array or object is stored. When writing classes, ask yourself whether this class can be effectively implemented as an invariant class, always worth it. You may be surprised to answer the answer.