Java foundation | Object source code analysis

  java

Object源码解析

Java is an Object-oriented language, everything can be regarded as an object in Java, and all objects in Java are inherited from Object class by default, so Dog Brother reviewed this class today.

Object 方法概览

The above figure shows that Object has 12 methods, among which registerNatives () is implemented by C language, which is beyond the scope of research.

1、getClass

/**
     * Returns the runtime class of this {@code Object}. The returned
     * {@code Class} object is the object that is locked by {@code
     * static synchronized} methods of the represented class.
*/
public final native Class<?> getClass();

The function of this method is to return the runtime Class of an object, and its return value is class type, class c = obj.getclass (); Through object C, we can obtain all member Methods of the object, each member method is a method object; We can also obtain all member variables of the object, each member variable is a Field object; Similarly, we can also get the Constructor of the object, which is a constructor object. This method is often used in reflection.

2、hashCode

/**
     * Returns a hash code value for the object. This method is
     * supported for the benefit of hash tables such as those provided by
     * {@link java.util.HashMap}.
*/
    public native int hashCode();

The annotation of this method is relatively long and will not be released. The note points out that:

  • The hashCode method returns a hash value.
  • The return value is converted by default from the address of the object.
  • The return value of the same object calling hashCode is equal.
  • If the equals of two objects are equal, then hashCode must be equal.
  • If the equals of two objects are not equal, then hashCode is not necessarily equal.

3、equals

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

Equals is very simple to implement. Its function is to compare whether two objects are equal, and the comparison is based on the memory addresses of the two objects. In addition, equals also follows the following principles:

1、自反性:x.equals(x);  // true
2、对称性:x.equals(y) == y.equals(x);  // true
3、传递性:if (x.equals(y) && y.equals(z))
            x.equals(z); // true;

4、一致性,只要对象没有被修改,多次调用 equals() 方法结果不变:
x.equals(y) == x.equals(y); // true 

5、非空性,对任何不是 null 的对象 x 调用 x.equals(null) 结果都为 false :
x.equals(null); // false;

Why rewrite hashcode and equals?

This question has been shared before:https://mp.weixin.qq.com/s/iI …

4、clone

protected native Object clone() throws CloneNotSupportedException;

Clone () is the protected method of Object. It is not public. One class cannot directly call the clone () method of this class instance without explicitly rewriting clone (). In addition, Clone’s comments also mentioned some important points:

  • The cloned object must implement the Cloneable interface and override the clone method, otherwise a CloneNotSupportedException exception will be reported.
  • The clone () method is not a method of the Cloneable interface, but a protected method of Object. The Cloneable interface only stipulates that if a class calls the clone () method without implementing the Cloneable interface, a CloneNotSupportedException will be thrown.
  • Shallow Copy: The reference type of the copy object and the original object refer to the same object.
  • Deep Copy: The reference types of the copied object and the original object refer to different objects.

For a detailed explanation of shallow copy and deep copy, please see this old article:
https://mp.weixin.qq.com/s/I6 …

5、toString

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

This method should have nothing to say, the original toString method only returns the object name+its hashCode, but all the developers know that the original toString has little effect. We need to rewrite toString generally because it is convenient to debug, and we need to know the attribute value of the object, not just hashCode. Therefore, it should be rewritten as follows:

public class Student {

    private int age;

    private String name;

    // 省略 get、set

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

6. notify and wait

public final native void notify();
public final native void notifyAll();

The first is notify, which will not be posted. notify is used to randomly wake up a thread in the waiting queue, while notifyAll is used to wake up all threads in the waiting queue.

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

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);
}

Then there is wait, whose function is to put the current thread into a waiting state. at the same time, wait () also makes the current thread release the lock it holds. Until another thread calls the notify () method or notifyAll () method of this object, the current thread is awakened into the ready state.

Wait(long timeout) (in milliseconds) puts the current thread in a wait (blocking) state until another thread calls the notify () method or notifyAll () method of this object or exceeds a specified amount of time, and the current thread is awakened into a ready state.

The function of wait(long timeout, intnano) is the same as that of wait (longtimeout). the only difference is that this can provide higher precision. The total timeout (in nanoseconds) is calculated as 1000000 *timeout+ nanos. By the way, wait(0,0) and wait(0) have the same effect.

In addition, the notify and wait comments also have such a paragraph:

* <p>
     * This method should only be called by a thread that is the owner
     * of this object's monitor. A thread becomes the owner of the
     * object's monitor in one of three ways:
     * <ul>
     * <li>By executing a synchronized instance method of that object.
     * <li>By executing the body of a {@code synchronized} statement
     *     that synchronizes on the object.
     * <li>For objects of type {@code Class,} by executing a
     *     synchronized static method of that class.
     * </ul>
* <p>

Seeing this English, I shivered a little after grade 4. The above comments mainly describe the usage specifications of notify and wait methods. This means that both must be used in synchronized decorated synchronization methods or synchronization codes.

  • Why must wait () be called in a Synchronized method/code block?

Answer: Calling wait () is to release the lock. The prerequisite for releasing the lock is to obtain the lock before releasing the lock.

  • Why must notify (), notifyAll () be called in a Synchronized method/code block?

Answer: notify () and notifyAll () are to give the lock to the thread containing the wait () method and let it continue to execute. If there is no lock of its own, how do you call the lock to be given to other threads? (Essentially, threads in the entry queue compete for locks)

Please refer to this blog post for detailed explanation:https://blog.csdn.net/qq_42145871/article/details/81950949

  • What is the difference between Thread.sleep () and Object.wait ()?

First, both can suspend the current thread and release CPU control. The main difference is that the Object.wait () releases the control of the object lock while releasing the CPU. Sleep () did not release the lock. In other words, sleep is to play rascal, occupying a dog in the manger.

Recommended reading:

1. java | What is Dynamic Proxy

2. SpringBoot | Startup Principle

3. SpringBoot | Automatic Configuration Principle

一个优秀的废人