Java 杂谈

Object详解

2019-06-29  本文已影响0人  alonwang

Object的方法列表如下.

Untitled-1c0375dd-9bb0-4900-b36a-367d6fa5bb5b.png

registerNatives — 自定义native方法命名

registerNatives完成自定义native方法命名,在静态代码块被调用完成命名的初始化.

对于带有native修饰的方法,JVM需要知道对应的native代码的方法命名.默认情况下,有一套默认规则.例如对于java.lang.Object.registerNatives,对应的C语言命名为Java_java_lang_Object_registerNatives.

假设有如下native方法

package com.github.alonwang
public RegisterNativesDemo{
    public native void nativeMethod();
}

默认生成的native方法命名为Java_com_github_alonwang_RegisterNativesDemo_nativeMethod.

而Object中的native方法通过registerNatives达成自定义命名,例如 Object.hashCode对应的native方法命名为JVM_IHashCode(参见这里).

clone — 生成实例拷贝

如果一个类实现了Cloneable接口(只是一个标记接口),就能调用clone方法生成当前实例的一份拷贝.只能完成浅拷贝.

public class CloneDemo implements Cloneable {
    private int a;
    private Integer A;

    public CloneDemo(int a, Integer a1) {
        this.a = a;
        A = a1;
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        CloneDemo a = new CloneDemo(1, 1);

        CloneDemo b = (CloneDemo) a.clone();
        System.out.println("a.a == b.a ? " + (a.a == b.a));
        System.out.println("a.A equals b.A ? " + (a.A.equals(b.A)));
        System.out.println("a.A == b.A ? " + (a.A == b.A));
    }
}

输出:

a.a == b.a ? true
a.A equals b.A ? true
a.A == b.A ? true

可以看到原实例和拷贝实例中的字段A,引用了同一个对象.任何一方修改A都会影响到另一方.

equals &&hashCode— 对象是否相等&哈希表

equals判定两个对象是否相等,需要满足以下条件

生成对象的哈希码,有如下约定:

  1. 如果两个对象根据equals比较相等,那么这两个对象的哈希码也相等(反之并不成立)
  2. 如果两个对象根据equals比较并不相等,不要求两个对象的哈希码不同(但是如果不同可以提高哈希表的性能)

对于Object而言,equals直接比较两个对象的内存地址,hashCode则是根据内存地址计算. 这符合Object的定义: 内存地址相同的对象才是相等的.

哈希表对equals和hashCode的要求

如果对象需要作为哈希表的key,就需要特别关注equals和hashCode的关系,先简单介绍下HashMap.get(key)的过程:

  1. 首先根据key的哈希码确定key在entry数组中的位置entry[i]

  2. 如果entry[i]为空,说明不存在,如果不为空,需要通过equals判断依次判断key和entry[i]链表中的key是否相等,如果相等,说明存在,否则说明不存在.

为了实现上面的过程,当equals与hashCode结合时,有如下关系:

  1. 必须同时覆盖equals和hashCode
  2. equals相等时,hashCode必须相等
  3. hashCode相等,equals不一定相等

那么何时需要覆盖equals和hashCode呢?

先来推断2,假设equals相等时,hashCode不相等,那么在11这一步,两个根据equals判定相等的key,对应的哈希码时不同的,因此在11中计计算出它们在entry数组中的位置也是不同的,这样就导致"相同"的key在hashMap中对应多个value. 这样显然违背了hashMap的定义,因此equals相等时,hashCode必须相等.

对于3,由22自然可以得出hashCode相等,equals不一定相等.

对于1, 如果未同时覆盖两者,很可能违背2.

总结一下,如果你要将对象作为哈希表中的key,才需要特别注意两者的关系,不然还是保持默认最好.

finalize — 对象的终结

一个对象真正被回收,至少需要经过两次标记

  1. 对经过可达性分析无法到达的对象进行第一次标记并筛选,如果对象覆盖了finalize方法且finalize方法没有被虚拟机调用过,有必要执行finalize方法,否则没有必要执行finalize方法,直接清理
  2. 如果对象被判定为有必要执行finalize方法,这个对象会被放置到一个称为F-Query的队列中,稍后由虚拟机创建的、低优先级的Finalizer会去执行(为了安全,会触发这个对象的finalize方法但不承诺会等待它运行结束)它,如果在finalize方法中对象重新与引用链上的任何一个对象建立联系,在第二次标记中就会被移除“即将回收”的集合,否则就真的被回收。

finalize在设计是是为了和C++保持兼容, 一个错误的说法是在finalize中执行资源的回收,事实上这是很不安全的.回收资源使用try,finally更为合适.<深入理解Java虚拟机>中建议忽略这个方法的存在

getClass — 获取Class对象

Class对象是JVM生成用来保存对象的类的信息的.通过Class对象可以获取类的元数据,通过反射获取类的实例,用途极广.

notify,notifyAll,wait — Java的底层同步机制

下面的代码分别演示了

toString — 生成对象的字符串表示

默认生成 类的名字@实例的哈希码的16进制,有时为了调试方便, 会覆盖toString输出更有用的信息


registerNatives: https://stackoverflow.com/questions/1010645/what-does-the-registernatives-method-do

wait/notify: https://juejin.im/post/5b612adbe51d4517df151e66

java Object: https://fangjian0423.github.io/2016/03/12/java-Object-method/

上一篇 下一篇

猜你喜欢

热点阅读