JDK1.8源码学习-Object

Posted liudblog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK1.8源码学习-Object相关的知识,希望对你有一定的参考价值。

JDK1.8源码学习-Object

目录

一、方法简介

1.一个本地方法,主要作用是将本地方法注册到虚拟机中。

private static native void registerNatives();
    static 
        registerNatives();
    

2.获取类的字节码对象

public final native Class<?> getClass();

3.返回当前对象的hash值

 public native int hashCode();

4.比较党当前对象的引用是否和要比较的对象的引用指向同一对象

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

5.克隆对象,浅拷贝

protected native Object clone() throws CloneNotSupportedException;

6.返回当前对象的一个字符串表示形式

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

7.唤醒一个正在等待该对象的线程,如果有多个线程等待,则只能唤醒其中一个

public final native void notify();

8.唤醒所有正在等待这个对象的线程

public final native void notifyAll();

9.阻塞当前线程,等timeout毫秒后会自动唤醒当前线程,当timeout为0时,表示不会自动唤醒线程

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

10.阻塞当前线程,等timeout毫秒后会自动唤醒当前线程,nanos为纳秒

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

11.阻塞当前线程

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

12.当垃圾回收器确定该对象在任何地方没有被引用时,会调用此方法进行垃圾回收

protected void finalize() throws Throwable  

二、方法详解

1.equals方法

在面试中经常会问道equals()方法和==运算的区别,==运算符用于比较基本类型的值是否相同而equals用于比较两个对象是否相等,在Object中equals与==是等价的,比较的是两个对象的引用,所以自定义对象的时候需要重写equals方法。在Java规范中,对equals方法的使用必须遵循以下几个原则:    

  • 自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。
  • 对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
  • 传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。
  • 一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改
  • 对于任何非空引用值 x,x.equals(null) 都应返回 false

  需要注意的是重写equals必须重写hashCode,且 

       X.equals(Y)==true,则X.hashCode()==Y.hashCode();

       X.hashCode()==Y.hashCode(),则X.equals(Y)不一定为true,也可能为false;

      具体原因可查看hashMap等集合源码。

 2. getClass方法 

      1.一个类的实例对象可以有很多,但是它的字节对象只有一个。

       2.一个对象可以被强转为其他对象但是其字节码不变。

public class App 
    public static void main(String[] args) 
 
        Class clazz1 = new Person().getClass();
        Class clazz2 = new Person().getClass();
        Class clazz3 = Person.class;
 
        System.out.println(clazz1 == clazz2);//true
        System.out.println(clazz1 == clazz3);//true
 
        System.out.println(Object.class == (Object)(new Person()).getClass());//false
        System.out.println(Person.class == (Object)(new Person()).getClass());//true
 
    

 
class Person
 

3.clone方法

浅拷贝与深拷贝的区别:

  浅拷贝:如果在一个对象的内部还有一个引用类型的变量,那么在拷贝对象的时候,clone方法新产生的对象只是拷贝了一个该基本类型的引用。

  深拷贝:如果在一个对象内部含有一个引用类型的变量,那么就会将该引用类型的变量指向的对象复制一份,然后引用该新对象。

  技术图片

4.toString方法

该方法返回一个能代表该对象的字符串,该字符串由类名以及该对象的十六进制的哈希值拼成。通常情况下,其子类需要覆写该方法。

5.finalize方法

垃圾回收器在认为该对象是垃圾对象的时候会调用该方法,子类可以通过重写该方法来达到资源释放的目的。

在方法调用过程中出现的异常会被忽略且方法调用会被终止。

任何该对象的方法只会被调用一次。

总结

  本地方法7个:

              private static native void registerNatives()

              public final native Class<?> getClass()

      public native int hashCode()

      protected native Object clone()

              public final void notify()

              public final native void notifyAll()

              public final native void wait(long timeout)

       非本地方法5个:

     public boolean equals(Object obj)

          public String toString()

       public final void wait(long timeout,int nanos)

       public final void wait()

       protected void finalize()

思考点:notify、notifyAll、wait这些和多线程有关的方法为什么定义在Object类中?

             1.在java的内置锁机制中,每个对象都可以成为锁,也就是说每个对象都是可以去调用这些方法的,而Object是所有类的父类,所以要把这些方法放到Object中。

             2.一个线程可以拥有多个对象锁,上面这些方法跟对象锁之间是有一个绑定关系的,比如用对象锁aObject调用的wait()方法,那么只能通过aObject.notify()或者aObject.notifyAll()来唤醒这个线程,这样JVM很容易就知道该从哪个对象锁的等待池中去唤醒线程,假如用Thread.wait()、Thread.notify()、Thread.notifyAll()来调用,虚拟机则无法判断要操作的对象锁是哪个。

以上是关于JDK1.8源码学习-Object的主要内容,如果未能解决你的问题,请参考以下文章

JDK1.8 CopyOnWriteArrayList源码学习

JDK1.8 Java小白的源码学习系列:HashMap

JDK1.8源码学习-String

ConcurrentLinkedQueue基于JDK1.8源码学习心得

JDK1.8源码分析02之阅读源码顺序

ArrayList源码解读(jdk1.8)