让你重新认识Object类

185 阅读6分钟

Object的所有方法

image.png

1、常用方法

equals(Object)

默认实现

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

此方法用来表示两个对象是否相等,Java类实现equals方法可以自定义对象相等的比较规则。

getClass()

Java native实现的方法,返回当前对象的运行时类的对象。

public final native Class<?> getClass();

hashCode()

返回对象的哈希代码值。支持此方法是为了保护哈希表(如 提供的 java.util.HashMap哈希表)。

每当在 Java 应用程序执行期间对同一对象多次调用该方法时,该方法必须始终返回相同的整数, hashCode 前提是不修改用于比较对象的信息 equals 。 从应用程序的一次执行到同一应用程序的另一次执行,此整数不必保持一致。 如果根据该方法两个对象相等,hashCode必相等,两个对象根据方法不equals相等,hashCode也不等 hashCode的规则可以提升Hash表的性能,减少哈希冲突。

toString()

默认实现是

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

如果子类不重写toString方法,则返回全类名+@+16进制的hashCode

2、线程相关方法

notify()/notifyAll()

wait(long,int)/wait(long)/wait()/wait0()

在Java中,每个对象都有两个池,锁(monitor)池和等待池 锁池
锁池:假设线程A已经拥有了某个对象的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程A拥有,所以这些线程就进入了该对象的锁池中。

等待池
等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁(因为wait()方法必须出现在synchronized中,这样自然在执行wait()方法之前线程A就已经拥有了该对象的锁),同时线程A就进入到了该对象的等待池中。如果另外的一个线程调用了相同对象的notifyAll()方法,那么处于该对象的等待池中的线程就会全部进入该对象的锁池中,准备争夺锁的拥有权。如果另外的一个线程调用了相同对象的notify()方法,那么仅仅有一个处于该对象的等待池中的线程(随机)会进入该对象的锁池.

notify 和 notifyAll 的区别
wait()
public final void wait() throws InterruptedException,IllegalMonitorStateException
该方法用来将当前线程置入休眠状态,直到接到通知或被中断为止。在调用 wait()之前,线程必须要获得该对象的对象级别锁,即只能在同步方法或同步块中调用 wait()方法。进入 wait()方法后,当前线程释放锁。在从 wait()返回前,线程与其他线程竞争重新获得锁。如果调用 wait()时,没有持有适当的锁,则抛出 IllegalMonitorStateException,它是 RuntimeException 的一个子类,因此,不需要 try-catch。

notify()
public final native void notify() throws IllegalMonitorStateException
该方法也要在同步方法或同步块中调用,即在调用前,线程也必须要获得该对象的对象级别锁,的如果调用 notify()时没有持有适当的锁,也会抛出 IllegalMonitorStateException。
该方法用来通知那些可能等待该对象的对象锁的其他线程。如果有多个线程等待,则线程规划器任意挑选出其中一个 wait()状态的线程来发出通知,并使它等待获取该对象的对象锁(notify 后,当前线程不会马上释放该对象锁,wait 所在的线程并不能马上获取该对象锁,要等到程序退出 synchronized 代码块后,当前线程才会释放锁,wait所在的线程也才可以获取该对象锁),但不惊动其他同样在等待被该对象notify的线程们。当第一个获得了该对象锁的 wait 线程运行完毕以后,它会释放掉该对象锁,此时如果该对象没有再次使用 notify 语句,则即便该对象已经空闲,其他 wait 状态等待的线程由于没有得到该对象的通知,会继续阻塞在 wait 状态,直到这个对象发出一个 notify 或 notifyAll。这里需要注意:它们等待的是被 notify 或 notifyAll,而不是锁。这与下面的 notifyAll()方法执行后的情况不同。

notifyAll()
public final native void notifyAll() throws IllegalMonitorStateException
该方法与 notify ()方法的工作方式相同,重要的一点差异是:
notifyAll 使所有原来在该对象上 wait 的线程统统退出 wait 的状态(即全部被唤醒,不再等待 notify 或 notifyAll,但由于此时还没有获取到该对象锁,因此还不能继续往下执行),变成等待获取该对象上的锁,一旦该对象锁被释放(notifyAll 线程退出调用了 notifyAll 的 synchronized 代码块的时候),他们就会去竞争。如果其中一个线程获得了该对象锁,它就会继续往下执行,在它退出 synchronized 代码块,释放锁后,其他的已经被唤醒的线程将会继续竞争获取该锁,一直进行下去,直到所有被唤醒的线程都执行完毕。

3、生成对象方法

Object()

构造方法

clone()

Person p = new Person(23, "zhang"); Person p1 = (Person) p.clone();

image.png

4、垃圾回收相关方法

finalize()

在Java9中标记为弃用,真正移除还有很长的路。 image.png

此方法的作用: finalize()方法中一般用于释放非Java 资源(如打开的文件资源、数据库连接等),或是调用非Java方法(native方法)时分配的内存(比如C语言的malloc()系列函数)。

存在的问题:
① 由于finalize()方法的调用时机具有不确定性,从一个对象变得不可到达开始,到finalize()方法被执行,所花费的时间这段时间是任意长的。我们并不能依赖finalize()方法能及时的回收占用的资源,可能出现的情况是在我们耗尽资源之前,gc却仍未触发,因而通常的做法是提供显示的close()方法供客户端手动调用。
② 重写finalize()方法意味着延长了回收对象时需要进行更多的操作,从而延长了对象回收的时间。
③ 若方法异常或者产生死锁影响GC

Java9之后建议
建议使用AutoCloseable或者Cleaner进行处理, 为了防止可能造成的多线程的延迟处理,许多对象回收前的处理都是单独通过一个线程完成的,这样能够保证执行性能的提高。

package test.com;

public class Member implements Runnable{
    public Member(){
        System.out.println("【构造】Born");
    }

    public void doSomething(){
        System.out.println("doing");
    }

    @Override
    public void run() {     // 执行清除的时候,执行的是此操作
        System.out.println("【回收】Death");
    }
}
package test.com;
import test.com.Member;

import java.lang.ref.Cleaner;

public class MemberCleaning implements AutoCloseable{    // 实现清除
    private static final Cleaner cleaner = Cleaner.create();    // 创建清除处理
    private Member member;
    private Cleaner.Cleanable cleanable;

    public MemberCleaning(Member member) {
        this.member = member;
        this.cleanable = this.cleaner.register(this,this.member);    // 注册使用的对象
    }

    @Override
    public void close() throws Exception {
        this.cleanable.clean(); // 启动多线程
    }
}
package test.com;

public class Main {
    public static void main(String[] args) throws Exception{
        Member m;
        try (MemberCleaning mc = new MemberCleaning(m=new Member())){
                // 中间可以执行一些相关的代码
            m.doSomething();
        }catch (Exception e){

        }
    }
}