[Java] Do you really understand Java's Object object?

Insert picture description here

1 Overview

Original: https://mp.weixin.qq.com/s?__biz=MzI4Njg5MDA5NA==&mid=2247484210&idx=1&sn=9d40e2e4c72f0727c7b7925cbe314fc0&chksm=ebd74233dca0cb2560677c7dc7746cf166195dchatchaechaecha 0,

Insert picture description here

In fact, it can be summarized into a few:

registerNatives()【底层实现、不研究】
hashCode()
equals(Object obj)
clone()
toString()
notify()
notifyAll()
wait(long timeout)【还有重载了两个】
finalize()

Object has a total of 11 methods, one of which is the underlying implementation registerNatives(), and two of them are overloaded methods of wait() and wait(long timeout, int nanos).

So what we really need to look at is 8 methods

There is one more attribute:

 /**
     * 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.
     *
     * <p><b>The actual result type is {@code Class<? extends |X|>}
     * where {@code |X|} is the erasure of the static type of the
     * expression on which {@code getClass} is called.</b> For
     * example, no cast is required in this code fragment:</p>
     *
     * <p>
     * {@code Number n = 0;                             }<br>
     * {@code Class<? extends Number> c = n.getClass(); }
     * </p>
     *
     * @return The {@code Class} object that represents the runtime
     *         class of this object.
     * @jls 15.8.2 Class Literals
     */
    public final native Class<?> getClass();

equals and hashCode methods

The quals and hashCode methods can be said to be the key questions of the interview. With String, it can be said that they are everywhere in the interview questions.

First, let's take a look at the native implementation of equals and hashCode in Object:

hashCode:

public native int hashCode();

equals:

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

They all look very simple:

hashCode()native方法底层实现了。

equals()就直接==判断是否相等了。

To be more clear about what they do, let’s read its notes:

Insert picture description here
Insert picture description here

According to the comments, we can summarize the following points:

  1. To rewrite the equals() method, you must rewrite the hashCode() method
  2. The equals() method defaults to compare the addresses of the objects, using the == equivalent operator
  3. The hashCode() method has the function of improving performance for objects whose bottom layer is a hash table
  4. The same object (if the object has not been modified): then repeatedly calling hashCode() then the returned int is the same!
  5. The hashCode() method is by default converted from the address of the object

The equals() method also has 5 default principles:

  1. Reflexivity—>Call equals() returns true, no matter who calls equals() on these two objects, it returns true
  2. Consistency—>As long as the object is not modified, the corresponding result will be returned after multiple calls!
  3. Transitivity—>x.equals(y) and y.equals(z) both return true, then you can get: x.equals(z) returns true
  4. Symmetry—>x.equals(y) and y.equals(x) should be equal.
  5. The incoming parameter is null, and the return is false

It is easy to understand why hashCode() uses hash table as the bottom layer to improve performance. Let's review the insertion of HashMap again:

Insert picture description here
If the hash values ​​are not equal, you can directly judge that the key is not equal!

equals and hashCode method override

The equals() method defaults to compare the addresses of the objects, and uses the == equivalent operator. But according to our normal development, comparing the object address is meaningless.

Generally, if we have two Address objects, as long as the province number, city number, and street number of these two objects are equal, we consider these two objects equal!

Insert picture description here

The equals and hashCode methods implemented by String

We may have heard it when we first learned: String has implemented equals and hashCode methods.

This is why, we can directly use String.equals() to determine whether two strings are equal!

Let's take a look at its implementation:

Insert picture description here

    /**
     * Returns a hash code for this string. The hash code for a
     * {@code String} object is computed as
     * <blockquote><pre>
     * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
     * </pre></blockquote>
     * using {@code int} arithmetic, where {@code s[i]} is the
     * <i>i</i>th character of the string, {@code n} is the length of
     * the string, and {@code ^} indicates exponentiation.
     * (The hash value of the empty string is zero.)
     *
     * @return  a hash code value for this object.
     */
    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;
    }

toString method

Next, we look at the toString method, which is also very simple:

Insert picture description here
The toString method is mainly used to identify the object:

Insert picture description here

We can see from the above results: we can't see anything in the results~

So we generally rewrite toString(), then the printed result is very convenient for us to debug!

  @Override
    public String toString() {
    
    
        return "Address{" +
                "provinceNo=" + provinceNo +
                ", cityNo=" + cityNo +
                ", streetNo=" + streetNo +
                '}';
    }

The following result looks much better:
Insert picture description here

clone method

Let's also take a look at its top note:

Insert picture description here
After reading the comments above, we can summarize the following points:

The clone method is used for object cloning. Generally, the object you want to clone is independent (separate from the original object)

A deep copy means that the member variables of the object (if it is a variable reference) should be cloned, and a shallow copy means that the member variable is not cloned.

Let's take a look at the shallow copy: the Employee object is copied, but its member variable hire has not been cloned out, so it points to the same Date object!

Insert picture description here

clone usage

So how do we clone objects? Both shallow copy and deep copy are two steps:

  1. The cloned object should implement the Cloneable interface
  2. Rewrite the clone method, preferably modified to public

Shallow copy: Only the Person object is copied, but date is not copied!

public class Person implements Cloneable {
    
    

    // 可变的成员变量
    private Date date;

    @Override
    public Object clone() throws CloneNotSupportedException {
    
    

        return super.clone();
    }

}

Deep copy: not only copies the Person object, but also the date member variable

public class Person implements Cloneable {
    
    

    // 可变的成员变量
    public  Date date;

    @Override
    public Object clone() throws CloneNotSupportedException {
    
    


        // 拷贝Person对象
        Person person = (Person) super.clone();

        // 将可变的成员变量也拷贝
        person.date = (Date) date.clone();


        // 返回拷贝的对象
        return person;
    }

}

4.2 clone question further study protected

I don’t know if anyone has the same question as me:

I only want a shallow copy, can I call the object .clone() directly to achieve it?

For example, I now have an Address object:

public class Address  {
    
    

    private int provinceNo;
    private int cityNo;
    private int streetNo;

    public Address() {
    
    
    }

    public Address(int provinceNo, int cityNo, int streetNo) {
    
    
        this.provinceNo = provinceNo;
        this.cityNo = cityNo;
        this.streetNo = streetNo;
    }
}

What do you think of the following code?

Address address = new Address(1, 2, 3);
    address.clone();

we all know:

protected修饰的类和属性,对于自己、本包和其子类可见

You may think: the clone() method is defined on the Object class (modified with protected), and our custom Address object implicitly inherits Object (all objects are subclasses of Object), then the subclass calls It is completely fine for Object to modify clone() with protected

However, IDE reality tells me that this compilation fails!

Insert picture description here
The reason for the error I immediately thought: Did I deviate from the protected modifier?

Protected modified classes and attributes are visible to yourself, this package and its subclasses. This sentence itself is not wrong. But it needs to be added: For protected members or methods, whether the molecular class and the super class are in the same package. Not with the base class 同一个包中的子类, only访问自身从基类继承而来的受保护成员,而不能访问基类实例本身的受保护成员。

The above code is wrong: Address and Object are not in the same package, and Address directly accesses the clone method of Object. This will not work.

Let me take two pictures and show them to you (after reading the pictures and then reading the above description, you can understand):
Insert picture description here
Insert picture description here

Five, wait and notify methods

The wait and notify methods are actually the API that Java provides us for communication between threads.

As usual, let’s look at what the comments say:

wait method:

Insert picture description here

notify method:

Insert picture description here

notifyAll() method:
Insert picture description here

After reading the comments above, we can summarize the following points:

  1. Whether it is wait, notify or notifyAll(), it needs to be called by the listener object (lock object)
    1. Simply put: they are all called in synchronous code blocks, otherwise an exception will be thrown!
  2. Notify() wakes up a thread in the waiting queue (not sure which one will wake up), notifyAll() wakes up all threads in the waiting queue
  3. There are 4 situations that cause the thread of wait() to be awakened
    1. The thread was interrupted
    2. wait() time is up
    3. Was awakened by notify()
    4. Waking up by notifyAll()
  4. The thread calling wait() will release the lock

In fact, after summarizing the above, you will not be deeply impressed. You can try to answer a few questions to deepen your understanding of wait() and notify().

Why wait and notify are on the Object method?

We have said from the beginning: wait() and notify() are APIs that Java provides us with communication between threads. Since it is a thread, what is defined on the Object class, not on the Thread class? ?

Because our 锁是对象锁[If you forget the students can review: understand the Java lock mechanism], every object can become a lock.让当前线程等待某个对象的锁,当然应该通过这个对象来操作了。

The lock object is arbitrary, so these methods must be defined in the Object class

What happens after the notify method is called?

As mentioned above, notify will wake up a thread in the waiting queue.

But it should be noted that:

After the notify method is called, the awakened thread will not immediately obtain the lock object. Instead, the lock object will be obtained after the synchronized code block of notify is executed.

What is the difference between sleep and wait?

Both Thread.sleep() and Object.wait() can suspend the current thread and release CPU control.

The main difference is that Object.wait() releases the control of the object lock while releasing the CPU.
And Thread.sleep() did not release the lock

Reference materials:

https://blog.csdn.net/lingzhm/article/details/44940823

http://www.cnblogs.com/dolphin0520/p/3920385.html

https://www.cnblogs.com/eer123/p/7880789.html

https://www.jianshu.com/p/f4454164c017

Guess you like

Origin blog.csdn.net/qq_21383435/article/details/108517875