Object类源码分析


前提概要


Object类结构图:

  • Java的世界里,什么东西都可以抽象成一个对象,而Object类就是所有对象的基类,所有对象,包括数组,都隐式的继承了Object类

  • Java8中的Object类,共有12个方法, 10类方法(不含重载); 其中clonefinalize是protected类型,registerNatives是private类型,其他都是public

重点注意


  • Object没有构造方法,只有一个由本地方法构成的静态方法
  • Object的很多方法都是final方法,而且很多是native方法
  • Object默认的hashCode()返回的不是对象的地址,而是对象地址带入算法计算得到的一串整型,并且equal相同的对象,的hashcode值也不同
  • toString()返回的不是对象的地址,而是对象的类名 + @ + 该对象hashcode的十六进制形式
  • clone()方法是保护的方法,通常的对象是无法调用clone方法的,除非重写clone方法,通过super.clone()形式访问,并且扩大访问修饰符;但没有实现Cloneable()的类随意调用clone方法时会报异常的
  • finalize()方法是一个空方法,默认实现是没有任何意义的;所以它就是用于给开发人员在需要的时候重写的

源码分析


构造方法
	 /**
     * Object对象比较特殊,他没有公有的构造方法
     * 所以只有一个由本地方法构成的静态方法,并有静态代码块来完成初始化
     */
    private static native void registerNatives();
    static {
        registerNatives();
    }

 
 
  • 具体是用C(C++)在DLL中实现的,然后通过JNI调用
  • 具体的地位,我们就可以比作是Object的构造方法

getClass方法
	/**
     * 公共方法:这是一个本地方法,且不可重写
     * 作用:获取当前对象的实际类类型
     *
     */
    public final native Class<?> getClass();

 
 
  • 这是一个公有的本地方法,但是不能够重写,因为它被final关键字所修饰
  • 通常我们可以通过getClass方法获的当前对象的类类型,既Class<?>对象(也可以说是该对象的元数据)
  • 获得的返回值可以判断出当前对象的运行时类型(实际类型,非静态类型)

hashcode方法
 /**
     * 公有方法:这是一个本地方法,默认的hashcode
     * 作用:返回该对象的hashcode
     * 返回值:int类型的hashcode
     *
     * 默认的hashcode方法总是返回10位的int类型,通常情况下
     * 我们的类都要重写Object的hashcode方法,以获得更好的hash优化
     *
     * @return
     */
    public native int hashCode();
  • 这是一个本地公有方法,当一个类没有重写hashCode方法时,就会默认使用Object的hashcode方法
  • 默认的hashcode方法总是返回10位的int数值,并且即使是equals相同的对象的hashcode都是不一定相同的。这是因为,Object的hashCode是基于对象的ID实现的,所以这也是为什么推荐总是重写hashcode方法的原因
  • 同时站在为不同的类实现相对于它们而言,更优的哈希算法角度,我们也应该重写hashcode方法。因为hashcode方法并不是所有类通用的。
  • 它返回的并不是该对象的地址,这是一个日常误解;而是虚拟机根据对象的地址带入一个算法中去计算得出的一串整数

为什么要重写hashcode()方法 - 作者:ServerSocket


equals方法
 	/**
     * 公有方法:非本地方法,比较函数
     * 作用:当前对象与参数对象进行比较,看是否是同一个对象
     * 
     * @param obj
     * @return
     */
    public boolean equals(Object obj) {
        return (this == obj);
    }

 
 
  • 因为Java中涉及到引用传递和值传递这种概念(当然也有说法说Java只有值传递,这只是不同的角度,不同的看法,我们这么不讨论这些无聊的问题)。而Object默认的equals的判断就是一种引用判断,既拿当前对象的地址与参数对象的地址进行比较,是内存中的同一个地址,则判断相同,不同地址,则不相同
  • 但是通常我们的equals是用于判断两个对象的值是否相同,而非判断地址,而且因为已经有了==的方式去判断地址。所以通常情况我们推荐把类的equals方法也要进行重写,而非使用Object默认的equals方法。既值判断使用equals,地址判断使用==

clone方法
    protected native Object clone() throws CloneNotSupportedException;

 
 
  • 保护方法,本地方法,可重写
  • 用于返回一个与调用对象一摸一样的克隆对象
  • 只有实现了Cloneable接口的类才可以调用clone();没有实现虽然也可以调用,但是会抛异常CloneNotSupportedException
  • 如果仅仅是相对对象而言,那么可以说是一种深拷贝;如果是数组,或者说该对象里面有成员属性也是对象;那么clone方法仅仅是将对象的外壳换了,内在成员的仍然是旧地址引用;
  • 因为clone是保护的方法,所以通常由子类重写clone方法,并扩大访问权限来提供对外访问(子类重写的访问修饰符必须等于或大于父类的访问修饰符)

toString方法
	/**
     * 公有方法:toString..没什么好说的
     * 返回值: 当前对象的类名 + @ + 该对象hashcode的十六进制形式
     * @return
     */
    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

 
 
  • Object的toString方法因为不具备什么可见性。即我们使用Object默认的toString方法输出出来,仅仅是一串前对象的类名 + @ + 该对象hashcode的十六进制形式,我们也不能知道这个对象实际的内容是什么;所以建议重写

notify, notifyAll ,wait 方法
	public final native void notify();
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">native</span> <span class="token keyword">void</span> <span class="token function">notifyAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>


<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">native</span> <span class="token keyword">void</span> <span class="token function">wait</span><span class="token punctuation">(</span><span class="token keyword">long</span> timeout<span class="token punctuation">)</span> <span class="token keyword">throws</span> InterruptedException<span class="token punctuation">;</span>


<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">void</span> <span class="token function">wait</span><span class="token punctuation">(</span><span class="token keyword">long</span> timeout<span class="token punctuation">,</span> <span class="token keyword">int</span> nanos<span class="token punctuation">)</span> <span class="token keyword">throws</span> InterruptedException <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>timeout <span class="token operator">&lt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">IllegalArgumentException</span><span class="token punctuation">(</span><span class="token string">"timeout value is negative"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>nanos <span class="token operator">&lt;</span> <span class="token number">0</span> <span class="token operator">||</span> nanos <span class="token operator">&gt;</span> <span class="token number">999999</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">IllegalArgumentException</span><span class="token punctuation">(</span>
                            <span class="token string">"nanosecond timeout value out of range"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>nanos <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        timeout<span class="token operator">++</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token function">wait</span><span class="token punctuation">(</span>timeout<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>


<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">void</span> <span class="token function">wait</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> InterruptedException <span class="token punctuation">{</span>
    <span class="token function">wait</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
  • 这里的四个方法都是用于配合同步代码块synchronized的。
  • 比如有一个把锁lock,a个线程获取了这个lock锁,并且调用了lock.wait()。那么线程a就会放弃该lock锁,并进入阻塞状态;只要当别的线程调用了lock.notify或notifyall;阻塞的a线程才会重新恢复,重新去竞争锁

finalize方法
	/**
	* 保护方法,非公开方法
	*
	*/
    protected void finalize() throws Throwable { }

 
 
  • 这个方法时非公开的方法,一般是垃圾收集器回收该对象的时候被自动调用的,算是该对象垃圾回收前死亡的救赎。
  • 即如果该对象要被垃圾回收时,在回收前,会先执行该对象的finalize方法,只要在这个方法中重新让该对象得到引用,那么该对象就不会被回收;但是要注意的是,对象可以会被多次回收,但finalize在该对象的生命周期中只会被执行一次,即仅仅是一次的免死令牌
  • 该方法可以被重写,因为默认实现是没有意义的,因为它什么都没有做

相关问题


为什么equals相同的对象,它们使用Object的hashcode方法得到的hashcode值会不一样?

hashCode() : For every object, JVM generates a unique number which is hashcode. It returns distinct integers for distinct objects. A common misconception about this method is that hashCode() method returns the address of object, which is not correct. It convert the internal address of object to an integer by using an algorithm. The hashCode() method is native because in Java it is impossible to find address of an object, so it uses native languages like C/C++ to find address of the object.

以上引入外文资料的一段话,翻译起来是说:

Java 虚拟机会每一个对象生成一个唯一的hashcode整数串;每一个对象都有一个唯一的整数串;通常有一种误会是说Object的默认hashcode方法返回的是该对象的地址,实际上这种说法是不正确的,它实际是将该对象的地址带入到一个算法中计算,得出的一串整数数字串;同时因为Java语言无法实现查找对象的地址,所以hashcode()方法才是一个native的方法,是通过本地语言C/C++去实现的


转载来源 SnailMann https://blog.csdn.net/SnailMann/article/details/85688936

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值