Description of Object class

The Object class is the ancestor of all classes in Java, and every class in Java is extended from it. When a class does not directly inherit from another class, it inherits Object by default. That is, any class inherits Object directly or indirectly. Methods that Object can access can be called by all classes.

All methods of the Object class

Structure diagram of the Object class

Object. The class source code

/* * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * /

package java.lang;

/**
 * Class {@code Object} is the root of the class hierarchy.
 * Every class has {@code Object} as a superclass. All objects,
 * including arrays, implement the methods of this class.
 *
 * @author  unascribed
 * @see     java.lang.Class
 * @since   JDK1.0 * /
public class Object {

    private static native void registerNatives();
    static{ registerNatives(); } public final native Class<? > getClass(); public native int hashCode(); public booleanequals(Object obj) {
        return (this == obj);
    }

    protected native Object clone() throws CloneNotSupportedException;

    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

    public final native void notify();

    public final native void notifyAll();

    public final native void wait(long timeout) throws InterruptedException;

    public final void wait(long timeout, int nanos) throws InterruptedException {
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                    "nanosecond timeout value out of range");
        }
        if (nanos > 0) {
            timeout++;
        }
        wait(timeout);
    }

    public final void wait() throws InterruptedException {
        wait(0);
    }

    protected void finalize() throws Throwable { }
}
 
Copy the code

1. GetClass method

public final native Class<? > getClass();Copy the code

Return the runtime class of this Object. The returned class objects are those locked by the static synchronized method representing the class. Cannot be overridden. To call it, it is usually used in conjunction with getName ().

The first stage of class loading is the process of loading a.class file into memory and generating a Java.lang.class object. The getClass () method simply gets this object, which is a collection of all the information about the runtime class of the object of the current class. This method is also one of the three types of reflection.

There are three ways of reflection:

  1. Object getClass ();
  2. The name of the class. The class;
  3. Class.forname ();
class extends ObjectTest {
    private void privateTest(String str) {
        System.out.println(str);
    }
    public void say(String str) {
        System.out.println(str);
    }
}
public class ObjectTest {
    public static void main(String[] args) throws Exception {
        ObjectTest  = new(a);// Get the Class object that the object is running on
        Class<? extends ObjectTest> aClass = .getClass();
        System.out.println(aClass);
        //getDeclaredMethod this method can get all methods, including private methods
        Method privateTest = aClass.getDeclaredMethod("privateTest".String.class);
        // Remove the restriction on Java access modifiers.
        privateTest.setAccessible(true);
        privateTest.invoke(aClass.newInstance(), "private method test");
        //getMethod can only retrieve public methods
        Method say = aClass.getMethod("say".String.class);
        say.invoke(aClass.newInstance(), "Hello World"); }}class test.
private method test
Hello World
Copy the code

2. RegisterNatives method

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

The static code block in this method is what a class is bound to execute during initialization, so the method is executed when the class loads, and the binding of the local method is registered through this method. Through the following part of the code for Thread.c in OpenJDK

...static JNINativeMethod methods[] = {
    {"start0"."()V",        (void *)&JVM_StartThread},
    {"stop0"."(" OBJ ")V", (void *)&JVM_StopThread},
    {"isAlive"."()Z",        (void *)&JVM_IsThreadAlive},
    {"suspend0"."()V",        (void *)&JVM_SuspendThread},
    {"resume0"."()V",        (void *)&JVM_ResumeThread},
    {"setPriority0"."(I)V",       (void *)&JVM_SetThreadPriority},
    {"yield"."()V",        (void *)&JVM_Yield}
};

JNIEXPORT void JNICALL
Java_java_lang_Thread_registerNatives(JNIEnv *env, jclass cls){ (*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods)); }...Copy the code

From the above code we can see that the registerNatives method is dynamically bound through the JNI_onload function.

The registerNatives method in the Object class is provided in more detail

3. The clone method

 protected native Object clone() throws CloneNotSupportedException;
Copy the code

The method is to protect and realize the object of shallow copy, only implements the Cloneable interface to invoke the method, otherwise throw CloneNotSupoortedException anomalies. A cloned object usually meets the following three rules:

  1. X.c lone ()! = x, the cloned object is not the same as the original object, pointing to a different memory address
  2. X.lone ().getClass () == x.getClass ()
  3. X.lone ().equals (x)

The default clone method is shallow copy. A shallow copy refers to an object that is referenced by a property within an object that only copies the address of the reference, but does not reallocate the memory of the referenced object. A deep copy recreates the referenced object.

For example, Employee has a field hireDay, which is not a variable of the basic data type, but a reference variable. After Clone, a new reference of the Date type will be generated, which points to the same Date object as the corresponding field in the original object. In this way, the cloned class shares some information with the original class, which is obviously a disadvantage. The process is shown below:

This is where we need to do a deep copy, with special treatment for fields that are not basic, such as hireDay in this case. We can redefine the Clone method to make hireDay special, as shown in the following code:

<span data-wiz-span="data-wiz-span" style="The font - size: 1.167 rem;">   class Employee implements Cloneable  {  
        public Object clone() throws CloneNotSupportedException  {  
         Employee cloned = (Employee) super.clone();  
      cloned.hireDay = (Date) hireDay.clone()  
      return cloned;  
        }  
   }</span>
Copy the code

A more detailed explanation

4. The toString method

public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
Copy the code

The toString method returns a string, where getClass ().getName () is the full class name of the returned object (including the package name), and integer.tohexString () is the string representation of the hash code that is returned as an unsigned hexadecimal Integer. In general we can override this method in a subclass.

5. Equals (important)

public boolean equals(Object obj) {
        return (this == obj);
    }
Copy the code

The equals () method returns true if this and obj refer to the same block of memory. The equals () method returns true if this and obj refer to the same block of memory. Otherwise return false.

Notes:

  1. Return false even if two different memory objects have exactly the same contents.
  2. If the equals method in Object returns true when we want two objects with different memory but the same content, then we need to override the equals method in the parent class.
  3. The String class has overridden the equals method of the Object class

The String class overrides the equals method of the Object class

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

String is a reference type. You can’t compare whether the reference is equal, but whether the contents of the String are equal is important.

In the Java specification, the use of equals must follow the following principles:

  1. Reflexivity: x.equals (x) should return true for any non-null reference value x.
  2. Symmetry: for any non-null reference values x and y, x.equals (y) should return true if and only if y.equals (x) returns true.
  3. Transitivity: for any non-null reference values x, y, and z, if x.equals(y) returns true, and y.equals (z) returns true, then x.equals(z) should return true.
  4. Consistency: Multiple calls to x.equals (y) always return true or false for any non-null reference values x and y, provided that the information used in the equals comparison on the object has not been modified.
  5. X.equals (null) should return false for any non-null reference value x.

Note that whenever you override this method, you usually have to override the hashCode method to maintain the general convention of the hashCode method, which states that equal objects must have the same hashCode.

6. HashCode method (important)

public native int hashCode();
Copy the code

The hashCode method is declared as a native value and returns the hashCode of the object. The value is an int and is used for the hash lookup, reducing the number of times you have to use equals in the lookup.

Hash algorithm, also known as hash algorithm, is the result of data generated by a particular algorithm directly specified to an address, the entire result is generated by the hashCode() method.

Here are four objects, A,B,C, and D, which generate three values using hashCode method. Note that the values generated by calling hashCode on A and B are the same, a.hashcode () = b.hashCode () =0x001. When we insert B, we find that B is going to be inserted where A is, and A is already inserted,Call equals () to see if A and B are the same. If A and B are the same, insert B. If they are different, insert B after A.

HashCode () requires:

  1. HashCode must return the same hash code no matter how many times the program is called, as long as the changes to the object do not affect the equals demerit.
  2. Two objects that return true via an equals call must have the same hashCode.
  3. The hashcodes of two objects that return false via equals do not need to be different; they can be the same.

HashCode ()

  • If the two objects are equal, their hash codes must be the same.
  • If two objects are not equal, their hash codes may be the same.
  • If two objects have the same hash code, they may not be equal.
  • If the hash codes of two objects are different, they must be different.

Notes:

The hash value is an int (takes up four bytes). To avoid overflows,

The hash codes of different objects should be as different as possible to avoid hash collisions. In other words, the elements obtained by the algorithm should be distributed as evenly as possible.

For a Map collection, it is best to choose the basic data type and the String type for the key, since both override the equals() and hashCode() methods as specified.

String hashCode

public int hashCode() {
        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

Hash sets are implemented as follows:

A HashSet requires that objects not be repeated, so it must internally compare each object that is added to it. The rule is to use the hashCode() method first. If hashCode() results are the same, then check the equals() method, and if hashCode() results are different. Then the two objects must be different, so the efficiency of comparison will be improved a lot!

7. Wait/notify/notifyAll method

Five overloaded methods and their source code

Wait method

 public final void wait() throws InterruptedException {
        wait(0);
    }
Copy the code
  • > This method is used to put the current thread into sleep until notified or interrupted.Before wait () can be called, the thread must acquire an object-level lock for the objectThat is, the wait () method can only be called within a synchronized method or synchronized block. After entering the wait () method, the current thread releases the lock. Threads compete with other threads to regain the lock before returning from wait (). If wait () is not holding the appropriate lock,The thrown IllegalMonitorStateException, which is a subclass of RuntimeException and, therefore, does not require a try-catch structure.

Wait (Long Timeout) method

public final native void wait(long timeout) throws InterruptedException;
Copy the code
  • > wait (long timeout);If the specified number of milliseconds is exceeded before the waiting thread is notified or interrupted, it regains the lock through a raceAnd returns from wait (Long Timeout).

Wait (long timeout, int nanos) method

 public final void wait(long timeout, int nanos) throws InterruptedException {
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                    "nanosecond timeout value out of range");
        }
        if (nanos > 0) {
            timeout++;
        }
        wait(timeout);
    }
Copy the code
  • > Parameter Description

Timeout: Maximum wait time (milliseconds)

Nanos: Additional time in the millisecond range (0-999999)

This method causes the current thread to wait until another thread calls the object’s notify() or notifyAll() method, or at the specified time that has passed. This method is similar to one of the parameters of the WAIT method, but it allows for better control of the amount of time to wait before a notification is abandoned.

Wait (long Timeout, int nanos) {wait (long Timeout, int nanos) {wait (long timeout, int nanos); The wait () method does not return any information. Generally, we can determine whether to call wait () by setting the flag bit, changing the value of the flag bit before notify, and reading the value of the flag bit after wait (). Of course, to ensure that the notify is not missed, we need another flag bit to loop to determine whether to call wait ().

Notify method

 public final native void notify();
Copy the code
  • The notify method is a final native method. Subclasses are not allowed to override this method.

The notify method is used to wake up random threads that are waiting for the current object monitor. In general, the notify method and wait method are used together to achieve the purpose of multi-threaded synchronization.

After a thread is awakened, the thread must first re-acquire the monitor lock of the object (which is surrendered after the thread calls the wait method on the object) before it can continue execution. A thread in the call of an object before the notify method must get to the object’s monitor (synchronized), otherwise will throw IllegalMonitorStateException anomalies. Similarly, a thread must obtain the monitor for an object before calling its wait method.

NotifyAll method

  public final native void notifyAll();
Copy the code
  • NotifyAll causes all threads that were in wait on the object to exit the wait state (that is, they are awakened from waiting for a notify or notifyAll, but cannot proceed any further because they have not yet acquired a lock on the object) and wait to acquire a lock on the object. Once the lock on the object is released (when the notifyAll thread exits the synchronized code block that calls notifyAll), they compete. If one of the threads acquired the lock, it would continue to execute, and after it exits the synchronized block and releases the lock, the other threads that have been awakened will continue to compete to acquire the lock, and continue until all of the awakened threads have executed.

Notes:

  1. Use wait (), notify (), and notifyAll () to lock the calling object.
  2. After the wait () method is called, the thread state changes from RUNNING to WAITING and the current thread is placed on the object’s wait queue.
  3. After the notify () or notifyAll () method is called, the waiting thread still does not return from wait (). The waiting thread does not have a chance to return from wait () until the thread that calls notify () or notifyAll () releases the lock.
  4. The notify () method moves a WAITING thread in the wait queue from the wait queue to the synchronous queue, while the notifyAll () method moves all threads in the wait queue to the synchronous queue, and the moved thread state changes from WAITING to BLOCKED.
  5. The wait () method returns only if the lock on the calling object is obtained.

Calling the wait() method on thread T1 releases the lock held by thread T1 and puts thread T1 into A Waiting state.

Thread T1 is Blocked from the synchronization queue until another thread calls the notify() or notifyAll() method of object A.

When t1 obtains the lock, the thread enters the Runnable state. When T1 obtains the CPU’s scheduling rights, the thread continues to execute.

If a thread calls the wait () method of an object, it is placed in the wait pool of the object, and threads in the wait pool do not compete for the lock of the object.

When a thread calls an object’s notifyAll () method (which wakes up all wait threads) or notify () (which wakes up only one wait thread at random), the awakened threads enter the object’s lock pool, and the threads in the wait pool compete for the object’s lock.

If a thread does not compete for the lock, it will remain in the lock pool and will only return to wait () if the thread calls wait () again. The thread contending for the object lock continues to execute until it finishes executing the synchronized block, at which point it releases the object lock, and threads in the lock pool continue to compete for the object lock.

Concurrent Java programming: collaboration between the threads (wait/notify/sleep/yield/join)

8. The finalize method

 protected void finalize() throws Throwable { }
}
Copy the code

This method is used to free up resources. Java allows you to define a method called Finalize () in your class. It works like this: Once the garbage collector is ready to free the storage space occupied by an object, it first calls its Finalize () method. The memory occupied by the object is not actually reclaimed until the next garbage collection action takes place.

Features:

  • Never call the Finalize method of an object actively, this method should be called by garbage collection mechanism.
  • Finalize method is appropriate to be called, and whether it is called is uncertain, so do not take Finalize method as a method that must be executed.
  • When the JVM executes to restore the Finalize method of an object, it may change the object or other objects in the system to reachable state.
  • When an exception occurs when the JVM calls the Finalize method, the garbage collection mechanism does not report the exception and the program continues to execute.

Note:

Because finalize method may not be executed, we should not use Finalize method when we want to clean up the open resources ina certain class.

The Java Finalize method summarizes and GC executes finalize process

conclusion

So I’m going to look at this Object, so I don’t forget its methods. There were also some problems along the way, most notably a further understanding of the equals and hashCode methods.

reference

  1. The Art of Concurrent Programming in Java

  2. Java Core Technologies Volume 1

  3. Deeper Understanding of the Java Virtual Machine. 2nd edition