Today just began to read effective Java, the Chinese version of the reading is very awkward, but feel a lot of harvest.
In addition, the content of this book is for Java 1.5 and 1.6.
Here's the 2nd Chapter: Creating and destroying the contents of an object.
First: Consider replacing the constructor with a static factory method
This article is intended for scenarios where you want to obtain an instance of a class. In general, to obtain an instance of a class is through a constructor (called a constructor in the book).
The most common constructor is this, with no return parameters, with the same name as the class name.
Public class a{ public A (int a) { // constructor contents ... }}
The so-called Static factory, is a static function, the name and the class name are different, the return value is the object of this class. The example is to convert a Boolean base type value into a Boolean object reference:
Public Static Boolean ValueOf (boolean b) { return b? Boolean.TRUE:Boolean.FALSE;}
The class can access its client through its static factory method (that is, to get an instance of the object), rather than through the constructor, then why do we use a static factory? What is the advantage of it?
Advantage One: Static Factory method has a name
If the constructor's parameters do not correctly describe the returned object, then the static factory is easier to use and the code is easier to read.
For example, a Class A, there are two parameters of different constructors, do two things, a, B. The code is as follows:
Public class a{ Public A (int. a,string s) { //do A } Public A (String s,int a) { // do B }}
This is an overload of the constructor, for different parameters to do different actions, but the user does not know at the time of the call which constructor does which activity, they may put the order of the parameters wrong, called the constructor that they do not want to use. The static factory method is unrestricted, depending on the behavior to be done to give the method a different name, such as DOA (), DoB (), so that the user can avoid the wrong call, but also enhance the readability of the code.
Advantage Two: You don't have to create a new object every time you call them
This is the characteristic of the static method, when declaring a method with static, this method can be called directly with the class name, without the need to call with the object.
For example, the method MethodA is a static method, belonging to class A, then you can call this: A.methoda (). Instead of a A = new A (); A.methoda ();
Static methods can return the same object for repeated calls, which helps the class tightly control which instances should exist at some point. This class is called an instance-controlled class . There are several reasons for using instance-controlled classes:
1. You can ensure that it is singleton (singleton), or not instantiated.
2. The immutable class can be made to ensure that no two equal instances exist, that is, a.equals (b) is true if and only if a==b. This allows the user to use the = = operator instead of the Equals method to improve performance.
Advantage Three: Static factory can return objects of any subclass of the original return type
The constructor returns only the objects of this class, and the static factory method can return this class and the subclass object of this class, which is a manifestation of polymorphism. With this static factory method, it is a good practice for the user to refer to the returned object through an interface, rather than through its implementation class.
For example, for a collection class, List L = new arraylist<string> (). List is an interface, and ArrayList is an implementation class. We can refer to it through the interface list, and not necessarily with the implementation class ArrayList. This has the benefit of changing the implementation class declaration only in this place when the program's implementation class changes.
At the same time, there is one: the class that the static factory method returns to belongs to, and can not be present when writing a class that contains the static factory method . For example: (I don't know if I understand right here)
Public class a{ publicstatic B method () { // static Factory method } }publicclassextends a{//B class implementation }
This flexible, static factory approach forms the basis for the service provider Framework . What do you mean by the service provider framework? The book is so defined:
It refers to a system in which multiple service providers implement a service that provides multiple implementations to the client and decouples them from multiple implementations.
There are 3 important components in the service provider framework: 1, the service interface. This is implemented by the provider. 2, provider registration API, which is used by the system to register the implementation, let the client access them. 3. The Service access API is the instance that the client uses to obtain the service.
My understanding is that these 3 components form a hierarchical structure. From top to bottom are 3,2,1. The user sees the 3 service access API, after the user calls 3, 3 calls the 2 provider registration API, learns the service implementation information (such as the provider, name, etc.), 2 calls the Service Interface 1 provided by different providers, and completes the service implementation. The user only knows the result (get a service), but does not need to know which provider is providing it, and does not need to know which specific service implementation interface is invoked.
Advantage Four: When creating instances of parameterized types, they make the code more concise
Description by code:
map<string,list<string>> m = new hashmap<string,list<string>>(); // declared here two times <String,List<String>> // The following is a static factory method, declared only once map<string,list<string>> m = hashmap.newinstance ();
Of course, static factory methods also have drawbacks.
Disadvantage One: class if there is a private constructor, you can not quilt class
disadvantage two: they are not actually any different from other static methods. you have no way of looking at the name, whether a static method is a static factory method or just a normal static method. Following the customary name can compensate for this disadvantage, the commonly used name is: Valueof,of,getinstance,newinstance,gettype,newtype.
In general, the author of this book recommends that we first consider static factory methods, rather than common constructors.
Second: Consider using the builder when you encounter multiple constructor parameters
Consider this scenario: we need a class to represent the nutrient label outside the packaged food. Several fields in these tags are required: The content per serving, the amount per tank, and calories. There are more than 20 optional domains: Total fat, saturated fat, trans fats, cholesterol, sodium and more. What kind of constructor or static factory method should be used to write such a class?
A common use is to provide overloaded constructors, which are implemented by overloading the parameters in the constructor. But when there are many parameters, the client code can be very difficult to write.
There is a second method, the JavaBean pattern, which calls a parameterless constructor to create an object, and then sets each of the necessary parameters with the setter method. However, this approach has serious drawbacks: it may cause JavaBean to be in an inconsistent state, and thread safety is difficult to guarantee.
The author proposes a third method: Builder. Instead of generating the desired object directly, the client invokes the constructor (or static factory) with all the necessary parameters to get a Builder object, and then the client invokes a setter-like method on the builder object to set each relevant optional parameter. Finally, the client calls the parameterless build method to generate the immutable object. This builder is the static member class of the class it builds.
Sounds a little complicated, on the code:
//Builder Pattern Public classnutritionfacts{Private Final intservingsize; Private Final intservings; Private Final intcalories; Private Final intfat; Private Final intsodium; Private Final intcarbohydrate; Public Static classbuilder{//Necessary Parameters Private Final intservingsize; Private Final intservings; //Optional Parameters Private Final intCalories=0; Private Final intFat=0; Private Final intSodium=0; Private Final intCarbohydrate=0; PublicBuilder (intServingsize,intservings) { This. servingsize=servingsize; This. servings =servings; } PublicBuilder Calories (intval) {Calories=Val; return This;} PublicBuilder Fat (intval) {Fat=Val; return This;} PublicBuilder Carbohydrate (intval) {Carbohydrate=Val; return This;} PublicBuilder Sodium (intval) {Sodium=Val; return This;} Publicnutritionfacts Build () {returnNewnutritionfacts ( This);} } Privatenutritionfacts (Builder builder) {Servingsize=builder.servingsize; ... }}
Client code:
New Nutritionfacts.builder (240,8). Calories (+). Sodium (. Carbohydrate). build ();
The builder mode simulates a named optional parameter.
Of course, the builder mode is more verbose, so it is only suitable for multiple parameters, and the number is variable, with optional parameters.
Article Three: Hardening the Singleton property with a private constructor or enumeration type
Singleton refers to a class that is instantiated only once. There are two ways of implementing this:
First, a public static member is a final domain.
Public class elvis{ publicstaticfinalnew Elvis (); Private Elvis () {...} Public void othermethods () {...}}
Second, the public member is a static factory method.
Public class elvis{ privatestaticfinalnew Elvis (); Private Elvis () {...} Public Static Elvis getinstance () {return INSTANCE;} Public othermethods () {...}}
The Singleton implemented using either of these methods will cause problems when deserializing, and a new instance will be created each time the deserialization is made .
From Java 1.5, there is a third way to write an enumeration type that contains a single element:
Public enum elvis{ INSTANCE; Public void Othermethod () {...}}
This approach is more concise and provides a free serialization mechanism to prevent multiple instantiation. Therefore , single-element enumeration types have become the best way to implement Singleton.
Fourth: The ability to harden non-instancing through a private constructor
There are some tool classes that may contain only static methods and static fields, and we don't want them to be instantiated (for example, ), but in the absence of a constructor, the compiler automatically provides a public, parameterless constructor. At the same time, it is not feasible to declare them as abstract classes in an attempt to force the class to be instantiated. Abstract classes can have subclasses, subclasses can be instantiated, and even statements can mislead users into thinking that the class is designed specifically for inheritance.
We only need to let the class contain a private constructor to do this. Of course, this also has a side effect that will make this class cannot be quilt-like. Because all constructors display or implicitly call the parent class constructor.
Fifth: Avoid creating unnecessary objects
Consider: string s = new String ("Abdcle"); This statement creates a new string instance each time it is executed, but these actions are unnecessary, and if the sentence is in a loop, it creates many unnecessary string instances. Change to String s = "abdcle" is better. (because Java has a constant buffer pool, string constants only need to be created once)
Another example:
Public Static void Main (string[] args) { = 0l; for (long i = 0; i < integer.max_value; i + +) {+ = i; } SYSTEM.OUT.PRINTLN (sum);}
This example has no problem with functionality, but is much slower. Because sum is declared as a long, it causes the program to construct 231 redundant long instances. So , take precedence over the basic type, not the boxed type, and be careful about the involuntary automatic boxing.
In addition, the cost of creating and recovering small objects is inexpensive, so it is not a good idea to maintain your own pool of objects to avoid creating objects, unless the objects are heavyweight (such as database connection pooling) because creating a database connection is expensive, so reusing these connections makes sense. )
Sixth: elimination of expired references
Consider an example of an implementation stack:
Public classstack{Privateobject[] elements; Private intSize = 0; Private Static Final intDefault_initial_capacity=16; PublicStack () {Elements=NewObject[default_initial_capacity]; } Public voidpush (Object e) {ensurecapacity (); Elements[size++] =e; } PublicObject Pop () {if(Size = = 0) throws Newemptystacexception (); returnelements[--size]; } Private voidensurecapacity () {...}}
This can happen with a memory leak. Because elements in the stack pop up, the elements that are ejected are not garbage collected, and they are not recycled even if the program using the stack no longer references those objects. Because the stack internally maintains an outdated reference to these objects.
If an object reference is unconsciously preserved, the GC will not process the object, and it will not handle other objects referenced by the object.
To fix this problem is simple, in the pop method of the stack, add a sentence: element[size] = null;
Another source of memory leaks is caching, in two cases: the first is that the element in the cache has been cleared in memory, and the element is invalid and should be cleared. The second is that the elements in the cache have not been accessed for a long time and should be replaced by this element.
The third source is the listener and other callbacks (this I have not touched, not written)
Seventh: Avoid using the Finalize method
The disadvantage of the Finalize method is that it cannot be guaranteed to be executed in a timely manner because the GC startup time is not deterministic. There is even no way to guarantee that it will be executed. So it can't be used to release resources, update persistent state, etc. This part should be done by try-finally.
If you do need to terminate the method, you only need to provide a display termination method, such as Inputstream,outstream,sql. Close () on the connection.
It is important to note that the end method chain is not automatically executed. That is, if the subclass overrides the finalization method, the end method of the parent class must be called manually in the child class's finalization method, otherwise the parent class's finalization method will not be executed.
Effective Java reading notes creating and destroying objects