Reprint---Write high-quality code: 151 recommendations for improving Java programs (3rd: Classes, objects, and methods ___ recommendation 41~46)

Source: Internet
Author: User
Tags shallow copy

Read Catalogue

    • Recommendation 41: Make multiple inheritance a reality
    • Recommendation 42: Make a tool class non-instantiated
    • Recommendation 43: Avoid shallow copies of objects
    • Recommendation 44: The use of a copy of a serialized object is recommended
    • Recommendation 45: Do not identify yourself when you overwrite the Equals method
    • Suggested 46:equals should consider a null value scenario
Back to top tip 41: Make multiple inheritance a reality

In Java, a class can be implemented in multiple implementations, but not multiple inheritance, meaning that a class can implement multiple interfaces at the same time, but cannot inherit multiple classes at the same time. But sometimes we do need to inherit multiple classes, such as the ability to have multiple classes of behavior, it is difficult to use single inheritance to solve the problem (of course, using multiple inheritance can be solved). Fortunately, the inner classes provided in Java can solve this problem in a tortuous way, so let's take a look at a case that defines a father and mother interface that describes the ideal situation where the father is strong, the mother is gentle, and the code is as follows:

Public interface Father {public    int strong ();} Interface Mother {public    int kind ();}

The return values of strong and kind represent strong and gentle indices, the higher the index, the higher the strength and tenderness, the same as the character set in the game, and we continue to look at the two implementations of father and mother:

Class Fatherimpl implements Father {    //Father's strong index is 8    @Override public    int Strong () {        return 8;    }} Class Motherimpl implements mother {    //Mother's gentleness index is 8    @Override public    int Kind () {        return 8;    }}

The father's strong index is 8, the mother's gentleness index is also 8, good match, then their sons and daughters must be better, we look at the son class, the code is as follows:

Class son extends Fatherimpl implements mother {    @Override public    int Strong () {        //son stronger than Father        return su Per.strong () + 1;    }    @Override public    int Kind () {        return new motherspecial (). Kind ();    }    Private class Motherspecial extends Motherimpl {        @Override public        int Kind () {            //Son's gentle index lowers            return Super.kind ()-1;}}    }

The son inherits from his father, becomes stronger than his father (strong method), while the son also has the advantage of the mother, but the gentle index is reduced. Notice that this constructs the Motherspecial class to inherit the mother class, that is, to obtain the mother class behavior and methods, which is also an important feature of the inner class: The inner class can inherit a class independent from the external class, to ensure the independence of the inner class, it is based on this point, multiple inheritance will be possible. This inner class of motherspecial is called the member inner class (also called the instance inner class, Instance Inner Class), let's look at the daughter class, the code is as follows:

Class daughter extends Motherimpl implements Father {    @Override public    int Strong () {        return new Fatherimpl () {            @Override public            int Strong () {                //daughter's strong index decreased by                return Super.strong ()-2;}        }. Strong ();    }}

The daughter inherited the current tenderness index, while also covering the father's strong index, not much explanation. Note the strong method of overwrite, here is the creation of an anonymous inner class (Anonymous Inner Class) to override the parent class method to complete the function of inheriting the father's behavior.

Multiple inheritance refers to a class can inherit the behavior and characteristics from many and one father at the same time, according to this definition, our son class, the daughter class has realized from the father and the mother to inherit all functions, should belong to the multi-inheritance, this is entirely attributed to the internal class, we need to use multiple inheritance, You can think about the inner class.

In real life, there is also a problem of multiple inheritance, the above example says descendants inherit the father also inherited the mother's behavior and characteristics, such as China's special animal "Sibuxiang" (Scientific name Elk), its shape "like deer non-deer, like horse non-horse, like cattle non-cattle, like donkey non-donkey", which you want to use a single inheritance is more troublesome If you use multiple inheritance, you can solve this problem well: Define deer, horse, ox, donkey four classes, and then build the Elk class of multiple internal classes, inherit them.

Back to top recommendation 42: Make a tool class non-instantiated

Java projects use a lot of tools, such as the JDK's own tool class Java.lang.Math, java.util.Collections, etc. are often used by us. Tool class methods and properties are static, do not need to generate an instance to access, and the JDK has done a good job, because do not want to be initialized, so set the constructor private access, indicating that the class itself, no one can produce an instance, we Take a look at the Java.lang.Math code:

Public final class Math {    /**     * Don ' t let anyone instantiate this class.     *    /Private Math () {}}

The reason for the "Don't let anyone instantiate this class." is to stay because the constructor for math is set to private: I'm a tool class, I just want other classes to be accessed through the class name, and I don't want you to access it through the instance object. This is sufficient in a platform or framework project. But if you have been told not to do so, you also want to generate a Math object instance to access static methods and properties (Java reflection is so developed, modify the access rights of a constructor is a breeze), then I do not guarantee correctness, hidden problems can erupt at any time! So do we have a better way of restricting the project? There, that is not only set to private permissions, but also throws an exception, the code is as follows:

Class utilsclazz{public    Utilsclazz () {        throw new Error ("Don t Instantiate" +getclass ())}    }

This ensures that a tool class is not instantiated and that all accesses are made through the class name. It is important to note that this tool class is not intended to be integrated, because if a subclass can be instantiated, the constructor of the parent class is called, but the parent does not have a constructor that can be accessed, and the problem arises.

Note: If a class does not allow instantiation, ensure that the "normal" channel cannot instantiate it.

Back to top tip 43: Avoid shallow copies of objects

We know that a class that implements the Cloneable interface means that it has the ability to be copied. If you overwrite the Clone () method, you will have full copy capability. The copy is run in memory, so it is much faster in terms of performance than the object directly generated by new, especially on large object generation, which makes performance improvements very noticeable. But the object copy also has a relatively easy to ignore problem: shallow copy (Shadow Clone, also known as shadow copy) has the problem that the object property copy is not complete. Let's look at this piece of code:

 1 public class Man implements cloneable {2 public static void Main (string[] args) {3//definition Father 4 P Erson f = new Person ("father"); 5//define the older son 6 person s1 = new person ("big son", f); 7//The youngest son's message was copied over by the older sons of 8 person s2 = S1.clone (); 9 S2.setname ("youngest"), System.out.println (S1.getname () + "Father is" + S1.getfather (). GetName ());     Ystem.out.println (S2.getname () + "Father is" + S2.getfather (). GetName ()); 12}13//name + private String name;15 Father-Private person father;17 (String _name) {publi name = _name;20}21     C Person (String _name, person _parent) {_name;24 = father = _parent;25}26 @Override28         Public Person Clone () {p = null;30 try {p = (person) super.clone (); 32 } catch (Clonenotsupportedexception e) {e.printstacktrace ();}35 return p;36 37}38/*setter and getter method slightly */40} 

In the program we describe a scenario in which a father, with two sons, is of the same size as the son, so the youngest son's object is generated by copying the object of the big Boy, and the output of the run is as follows:

    The father of the older son is the father
The youngest son's father is the father.

  That's right, no problem. Suddenly one day, father whim want to let the big son to recognize a godfather, that is, the father of the big son name needs to be reset, the code is as follows:

    public static void Main (string[] args) {        //define father person        f = new Person ("father");        Define the big son person        s1 = new Person ("big son", f);        The youngest son's message was copied over by the big boy        s2 = S1.clone ();        S2.setname ("youngest son");        S1.getfather (). SetName ("Godfather");        System.out.println (S1.getname () + "Father is" + S1.getfather (). GetName ());        System.out.println (S2.getname () + "Father is" + S2.getfather (). GetName ());    }

The older son re-set the father's name, we expect the output is: the father of the older son to change the name of the father-in-the-godfather, the youngest son's dad name remains unchanged. Run the results as follows:

The father of the older son is the Godfather.
The youngest son's father is a godfather.

  What is the matter, the youngest son's father has become the "godfather"? Two sons all Wood has, this Lao Tze estimate is to be angry to die! The reason for this problem is that the Clone method, we know that all classes inherit from Object,object provides an object copy of the default method, that is, the page code in the Super.clone () method, but the method is flawed, he provides a shallow copy, This means that it does not copy all of the properties of the object, but a copy of the selection, with the following copy rules :

    1. Base type: If the variable is a base type, copy its value. such as int, float, etc.
    2. Object: If the variable is an instance object, copy its address reference, which means that the copied object shares the instance variable with the original object and is not controlled by access rights, which is crazy in Java because it breaks through the definition of access: A private modified variable, can be accessed by two different instance objects, which makes Java's access rights system.
    3. String string: This is special, the copy is an address, is a reference, but when modified, it will regenerate a new string from the string pool, the original string object remains unchanged, where we can think of a string is a basic type.

Understanding these three principles, the above example is very clear. The youngest son's object was a copy of the Big Boy, whose father was the same person, that is, the same object, the older son changed his father's name, the youngest son was also very modified-so the father's two sons are gone. In fact, to correct is also very simple, the code of the Clone method is as follows:

Public Person Clone () {person        p = null;        try {            p = (person) super.clone ();            P.setfather (New Person (P.getfather (). GetName ()));        } catch (Clonenotsupportedexception e) {            e.printstacktrace ();        }        return p;    }

And then run, the younger son's father will not be the Godfather, so that the deep copy of the object to achieve the self-contained, to ensure that the copy of the object is not affected by the "mother", and the object of the new generation is no different.

 Note: Shallow copy is just a simple copy mechanism provided by Java and is not easy to use directly.

Back to top recommendation 44: Use a copy of the serialized object is recommended

The previous suggestion that the object's shallow copy problem, the test Cloneable interface has the ability to copy, then we think about the question: If a project has a large number of objects are generated through the copy, then we how to deal with it? Each class is tied to a clone method and has a deep copy? Think about what a huge workload it is! Is there a better way to do it?

In fact, can be processed by serialization, in memory through the byte stream copy to achieve, that is, the mother object written into a byte stream, and then read it out of the byte stream, so that you can reconstruct an object, the new object and the parent object does not have a reference sharing problem, it is equivalent to a deep copy of an object, The code is as follows:

 1 Import Java.io.ByteArrayInputStream; 2 Import Java.io.ByteArrayOutputStream; 3 Import java.io.IOException; 4 Import Java.io.ObjectInputStream; 5 Import Java.io.ObjectOutputStream; 6 Import java.io.Serializable; 7 8 Public Final class Cloneutils {9 private cloneutils () {Ten throw new Error (Cloneutils.class + "cannot in Stance "); 11}12 13//Copy an object in public static <t extends serializable> T clone (T obj) {15//Copy Production  Raw Object cloneobj = null;17 try {18//Read object byte data bytearrayoutputstream BAOs = new Bytearrayoutputstream (); ObjectOutputStream oos = new ObjectOutputStream (BAOs); oos.writeobje CT (cloneobj); Oos.close (); 23//Allocate memory space, write to original object, generate new object Bytearrayinputstream Bais = NE             W Bytearrayinputstream (Baos.tobytearray ()); ObjectInputStream ois = new ObjectInputStream (Bais); 26 Return the new object and do type conversion cloneobj = (T) OIS.REadobject (); Ois.close (); catch (ClassNotFoundException e) {e.printstacktrace (); 3  1} catch (IOException e) {e.printstacktrace ();}34 return cloneobj;35 36}37 38}

This tool class requires the copied object to implement the Serializable interface, otherwise there is no way to copy (of course, using reflection is another technique), the previous example is only slightly modified to achieve a deep copy, the code is as follows

public class person implements serializable{    private static final long serialversionuid = 4989174799049521302L;        /* Remove Clone method, other code remains the same */}

The copied class as long as the implementation of serializable this iconic interface can be, do not need any implementation, of course, Serialversionuid constant is to add, and then we can use the Cloneutils tool to carry out the deep copy of the object, There are two points to note when using the Word method for object copying:

    1. The intrinsic properties of an object are serializable: if there are internal properties that are not serializable, a serialization exception is thrown, which makes the debugger wonder how a serialized exception can be generated when an object is built. From this point of view, it is also necessary to refine the Cloneutils tool's exception.
    2. Note the special modifiers for methods and properties: For example, the serialization of a final,static variable is introduced into the object's copy, which requires special attention, while the transient variable (transient variable, non-serialized variable) also affects the copy effect. Of course, there is an easier way of using serialized copies, which is to use the Serializationutils class in the Commons toolkit under Apache, which is straightforward to use.
Back to top tip 45: Do not identify yourself when you overwrite the Equals method

When we write a javabean, we often overwrite the Equals method, which is designed to determine whether two objects are equal according to business rules, such as when we write a person class and then determine whether two instance objects are the same by name, which in DAO (Data Access Objects) layers are often used. When you do this, get two DTOs (data Transfer object, data transfer objects) from the database, and then determine if they are equal, and the code is as follows:

public class Person {    private String name;    Public person (String _name) {        name = _name;    }    Public String GetName () {        return name;    }    public void SetName (String name) {        this.name = name;    }        @Override public    boolean equals (Object obj) {        if (obj instanceof person) {person            P = (person) obj;            Return Name.equalsignorecase (P.getname (). Trim ());        return false;    }}

Overwrite the Equals method to do a number of checks, considering that the Web upload passed the object may have entered before and after the space, so cut with the trim method, to see if the code is not a problem, we write a main:

public static void Main (string[] args) {person        p1= new person ("Zhang San");        Person p2= The new person ("Zhang San  ");        list<person> list= new arraylist<person> ();        List.add (p1);        List.add (p2);        System.out.println ("The list contains Zhang San:" +list.contains (p1));            System.out.println ("The list contains Zhang San:" +list.contains (p2));    }

The above code produces two person objects (note that the Zhang San in the P2 variable has a space behind it), and then it is placed in the list and finally determines whether the list contains the two objects. Look no problem, you should print out two true, but the result is:

Whether the list contains Zhang San: true
Whether the list contains Zhang San: false 

The object just put in the list said no, this is disappointing, why? The list class checks whether the containing element is always judged by invoking the Equals method of the object, that is, contains (P2) is passed in, executes P2.equals (p1) sequentially, p2.equals (P2), and only one returns true, and the result is true. Unfortunately, the comparison is false, and the problem comes out:

P2.equals (p2) because false?

That's true, P2.equals (P2) is really false, look at our equals method, it cuts the second parameter! In other words, the following equation is compared:

"Zhang San  ". Equalsignorecase ("Zhang San");

Note that the front of the Zhang San, there is a space, the result is definitely false, the error also arose, this is a good thing but to do a "bad" case, it violates the Equlas method of the reflexive principle: For any non-null reference x,x.equals (x) Should return true, the problem until the resolution is very simple, just remove trim (). Note that only the current problem is resolved, and there are other issues with the Equals method.

Back to top recommended 46:equals should consider a null value scenario

Continuing with the 45 suggested questions, we solved the question of the reflexive nature of the overwrite equals, is it perfect? To refactor the Main method:

public static void Main (string[] args) {person        p1= new person ("Zhang San");        Person p2= the new person (NULL);
/* No changes in other parts, no more repeating */}

Very small changes, you must know that the result is the package "null pointer" exception. The reason is also very simple: the Null.equalsignorecase method naturally error, here is to illustrate the principle of the Equals method to follow one of the principles---

  Symmetry principle: For any case that references X and Y, if X.equals (y), y.equals (x) should also return true.

The solution is also very simple, the front plus non-empty judgment can be, very simple, do not paste code.

Reprint---Write high-quality code: 151 recommendations for improving Java programs (3rd: Classes, objects, and methods ___ recommendation 41~46)

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.