Object the superclass

Java is a natural object-oriented language. And all the classes that we create by hand, they all inherit from the same class, the Object class.

Take a look at the structure of the Object class

Native method

First, the superclass has a native method

private static native void registerNatives(a);
static {
    registerNatives();
}
Copy the code

In Java, functions decorated with native keywords indicate that the implementation of this method is not done in Java. Instead, it is done by C/C++ and compiled into a.ddL file, which is called by Java. The registerNatives() method itself mainly maps methods in C/C++ to native methods in Java to achieve method naming decoupling. At the same time, a static code block is also defined. Therefore, whenever we create Java objects, the system always calls the static code block first, that is, calls the native method. The method is decorated private, indicating that the method is private and cannot be called externally

GetClass method

Using this method, you get a Class instance of the Class, which shows the Java reflection mechanism

HashCode methods

The definition of Baidu Encyclopedia is as follows:

HashCode is not completely unique. It is an algorithm that allows objects of the same class to have different hash codes according to their different characteristics, but does not mean that different object hash codes are completely different. The same is true of how programmers write hash codes.

A Hash table (also called a Hash table) is a data structure that accesses records based on Key values mapped to a location in the table to speed up search.

As a result, Java’s internal hash function can allocate a memory address to each instantiated object and record it in the hash table, which makes it easier to find, create, and compare objects in the program more efficiently.

Write an example to print and see:

public class base {

    public static void main(String[] args) {

        Apple apple = new Apple();
        System.out.println(apple.hashCode());
        System.out.println(apple);
        System.out.println(Integer.valueOf("74a14482".16)); }}class Apple {}Copy the code

Print result:

1956725890 p2.Apple@74a14482 1956725890 The process has ended. Exit code 0Copy the code

The hash address of the visible object is a base 10 number, corresponding to the printed native hexadecimal address

The equals method

The Object equals() method is used to compare whether two objects are equal.

The equals() method compares two objects to determine whether they refer to the same object.

You can see that when equals compares two objects for equality, it compares their Hashcodes for equality. Therefore, if you want to override equals, you usually override hashCode as well.

For example, String is not a native data type (such as int, char, double, etc.), but rather an object that Java has rewrapped. String, Integer, etc. override equals to compare values for equality instead of referencing types (hashcode).

For example, String rewraps the equals method:

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while(n-- ! =0) {
                    if(v1[i] ! = v2[i])return false;
                    i++;
                }
                return true; }}return false;
    }
Copy the code

Instanceof is the Reserved Java keyword. It tests whether the object to its left is an instance of the class to its right, returning Boolean data types. If the references are the same, return true; otherwise, the String instance is converted to an array of characters and matched one by one for equality, that is, for matching values.

String also overrides the hashCode method:

 public int hashCode(a) {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }
Copy the code

The default hash value is 0. Therefore, rewrite the hash formula as follows: hash=s[0]*31^(n-1) + S [1]*31^(n-2) +… + s[n-1]

== and equals

  • == : When comparing basic types, the values of the two types are compared for equality; When comparing reference types, reference references (HashCode) are compared for equality

  • Equals: Uses the source code to compare references to equals. Parts of types such as String and Integer override the equals method to compare values

A few examples:

public class base {

    public static void main(String[] args) {

        // new two strings with the same content
        String a = new String("xxx");
        String b = new String("xxx");
        System.out.println(a == b);    // Compare hash values because they are two different instantiated objects, return false
        System.out.println(a.equals(b)); // Compare the contents, both "XXX", return true

        // Generate two references
        String c = "xxx";
        String d = "xxx";
        System.out.println(c == d); // Compares the hash value, which is identical because it refers to the same reference, and returns true
        System.out.println(c.equals(d)); // Compare the contents, both "XXX", return true}}Copy the code

Equals equals equals equals equals equals equals equals equals equals equals equals equals equals equals equals

Clone method

The Object Clone () method is used to create and return a copy of an Object.

The Clone method is a shallow copy, in which the object referenced by the attribute in the object will only copy the referenced address without reallocating the memory of the referenced object, while the corresponding deep copy will also recreate the referenced object.

According to the source document, the Clone method can only implement a shallow copy, and the class needs to override the Clone method and call super.clone to get the returned object, because the instance method subclass protected by the base class has no access under different packages. In addition, the object class itself does not implement the Cloneable interface, but we write their own class needs to inherit the Cloneable interface, otherwise you will always throw CloneNotSupportedException anomalies.

Write an example:

public class base{

    public static void main(String[] args) throws CloneNotSupportedException {

        // instantiate a Student object
        Student student = new Student(18."Tony");
        // Print the content
        System.out.println(student);

        // Clone student instance
        Student anotherStudent = (Student) student.clone();
        // Print the clone contentSystem.out.println(anotherStudent); }}class Student implements Cloneable {
    int age;
    String name;

    Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    protected Object clone(a) throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString(a) {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\' ' +
                '} '; }}Copy the code

Print result:

Student{age=18, name='Tony'} Student{age=18, name='Tony'Copy the code

Shallow copy and deep copy

Shallow copy example

When the member of the copied object has a reference object, such as when the Student class contains another Teacher object, the cloned object and the cloned object point to the same Teacher reference, so when the Teacher data is changed, the cloned object also changes

Write an example:

public class base {

    public static void main(String[] args) throws CloneNotSupportedException {

        // instantiate a Teacher object
        Teacher teacher = new Teacher(25."JayChou");
        // instantiate a Student object
        Student student = new Student(18."Tony",teacher);
        // Print the content
        System.out.println(student);
        // Clone student instance
        Student anotherStudent = (Student) student.clone();
        System.out.println(anotherStudent);
        System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -");
        // modify teacher data and update student
        teacher.setAge(30);
        student.setTeacher(teacher);
        // Prints the modified student instance and cloned object instanceSystem.out.println(student); System.out.println(anotherStudent); }}class Student implements Cloneable {
    int age;
    String name;
    Teacher teacher;

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    Student(int age, String name, Teacher teacher) {
        this.age = age;
        this.name = name;
        this.teacher = teacher;
    }

    @Override
    protected Object clone(a) throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString(a) {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\' ' +
                ", teacher=" + teacher +
                '} '; }}class Teacher implements Cloneable {
    int age;
    String name;

    Teacher(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    protected Object clone(a) throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString(a) {
        return "Teacher{" +
                "age=" + age +
                ", name='" + name + '\' ' +
                '} '; }}Copy the code

Print result:

Student{age=18, name='Tony', teacher=Teacher{age=25, name='JayChou'}} Student{age=18, name='Tony', teacher=Teacher{age=25, name='JayChou'}} --------------------------------------- Student{age=18, name='fuck', teacher=Teacher{age=30, name='JayChou'}} Student{age=18, name='Tony', teacher=Teacher{age=30, Name ='JayChou'}} Process terminated, exit code 0Copy the code

This is the result of a shallow copy, which points to the same reference and causes cascading changes when one of the instances is updated

So instead, implement deep copy so that there is no chain reaction and the clone is completely separated from the cloned object!

Implementing deep copy

Have a general idea:

  • Instead of using the Clone method, create a new object and place all the attribute members of the object to be copied
 // instantiate a Teacher object
        Teacher teacher = new Teacher(25."JayChou");
        // instantiate a Student object
        Student student = new Student(18."Tony",teacher);
        // Print the content
        System.out.println(student);
        // create a new one!
        Student anotherStudent = new Student(18."Tony".new Teacher(25."JayChou"));
        System.out.println(anotherStudent);
        System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -");
        // modify teacher data and update student
        teacher.setAge(30);
        student.setTeacher(teacher);
        // Prints the modified student instance and cloned object instance
        System.out.println(student);
        System.out.println(anotherStudent);
Copy the code

Print result:

Student{age=18, name='Tony', teacher=Teacher{age=25, name='JayChou'}} Student{age=18, name='Tony', teacher=Teacher{age=25, name='JayChou'}} --------------------------------------- Student{age=18, name='Tony', teacher=Teacher{age=30, name='JayChou'}} Student{age=18, name='Tony', teacher=Teacher{age=25, Name ='JayChou'}} Process terminated, exit code 0Copy the code
  • Rewrite the clone method to clone each reference object as well
@Override
    protected Object clone(a) throws CloneNotSupportedException {
        Student student = (Student) super.clone();
        student.setTeacher((Teacher) this.teacher.clone());
        return student;
    }
Copy the code

Print result:

Student{age=18, name='Tony', teacher=Teacher{age=25, name='JayChou'}} Student{age=18, name='Tony', teacher=Teacher{age=25, name='JayChou'}} --------------------------------------- Student{age=18, name='Tony', teacher=Teacher{age=30, name='JayChou'}} Student{age=18, name='Tony', teacher=Teacher{age=25, Name ='JayChou'}} Process terminated, exit code 0Copy the code
  • serialization

There are many ways to serialize, mainly with more tools… Here I use Apache Commons Lang serialization

First, the related classes need to inherit the serialization interface (the interface has no real implementation content, just as a token)

public class base {

    public static void main(String[] args) throws CloneNotSupportedException {

        // instantiate a Teacher object
        Teacher teacher = new Teacher(25."JayChou");
        // instantiate a Student object
        Student student = new Student(18."Tony",teacher);
        // Print the content
        System.out.println(student);
        // Serialize deep copy
        Student anotherStudent = (Student) SerializationUtils.clone(student);
        System.out.println(anotherStudent);
        System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -");
        // Prints serialized content as a byte stream
        byte[] res = SerializationUtils.serialize(student);
        System.out.println(SerializationUtils.serialize(student));
        // Prints deserialization results
        System.out.println(SerializationUtils.deserialize(res));
        System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -");
        // modify teacher data and update student
        teacher.setAge(30);
        student.setTeacher(teacher);
        // Prints the modified student instance and cloned object instanceSystem.out.println(student); System.out.println(anotherStudent); }}class Student implements Serializable {
    int age;
    String name;
    Teacher teacher;

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    Student(int age, String name, Teacher teacher) {
        this.age = age;
        this.name = name;
        this.teacher = teacher;
    }

    @Override
    public String toString(a) {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\' ' +
                ", teacher=" + teacher +
                '} '; }}class Teacher implements Serializable {
    int age;
    String name;

    Teacher(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString(a) {
        return "Teacher{" +
                "age=" + age +
                ", name='" + name + '\' ' +
                '} '; }}Copy the code

Print result:

Student{age=18, name='Tony', teacher=Teacher{age=25, name='JayChou'}} Student{age=18, name='Tony', teacher=Teacher{age=25, name='JayChou'}} --------------------------------------- [B@50040f0c Student{age=18, name='Tony', teacher=Teacher{age=25, name='JayChou'}} --------------------------------------- Student{age=18, name='Tony', teacher=Teacher{age=30, name='JayChou'}} Student{age=18, name='Tony', teacher=Teacher{age=25, Name ='JayChou'}} Process terminated, exit code 0Copy the code

Conclusion: The first method is clumsy, while the second method requires manual rewriting of the Clone method, which is not a wise choice when the object is complex. In contrast, the third one is very convenient and handsome, but has some system overhead due to the complexity of the underlying implementation.

The toString method

When this method is not overridden, a hexadecimal concatenated string of the class name and hash address is returned when the instantiated object is printed. It is recommended that all subclasses override this method for human readability

For example, my Student class overrides this method:

class Student implements Serializable {
    int age;
    String name;
    Teacher teacher;

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    Student(int age, String name, Teacher teacher) {
        this.age = age;
        this.name = name;
        this.teacher = teacher;
    }

    @Override
    public String toString(a) {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\' ' +
                ", teacher=" + teacher +
                '} '; }}Copy the code

Print the object and return human-readable content:

Student{age=18, name='Tony', teacher=Teacher{age=25, name='JayChou'}}
Copy the code

Thread method

Wait (),wait(long),wait(long,int),notify(), and notifyAll() are used to sleep and wake up threads respectively

The finalize method