天天看点

JDK1.8源码阅读记录lang包object类JDK1.8源码阅读记录

JDK1.8源码阅读记录

JAVA.LANG包

Object类

registerNatives()

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

native关键字说明该方法是原生函数,即该方法是基于C/C++实现的,并被编译成了DLL,由Java调用,验证了Java是由C/C++编写出来的语言。实际上Java就是在不同的平台上调用不同的native方法实现对操作系统的访问的,所以Java具有跨平台的特性。

static说明该方法是静态方法,可以由 类.方法名() 进行调用。

native是调用本地实现方法,registerNatives则是对本地方法注册,装载本地库。在Object初始化时执行。

getClass()

public class SecondClass extends FirstClass {
    public SecondClass() {
    }
}
           

2.主函数

public class Main {
    public static void main(String[] args) {
        FirstClass firstClass1=new SecondClass();
        FirstClass firstClass2=new FirstClass();
        System.out.println(firstClass1.getClass());
        System.out.println(firstClass2.getClass());
        System.out.println(FirstClass.class);
    }
}
           

3.输出结果

JDK1.8源码阅读记录lang包object类JDK1.8源码阅读记录

结论:

对象.getClass() 方法返回的结果与 类.class属性一样的。

若有继承关系,通过子类构造父类的对象,该对象的对象.getClass() 方法将返回子类的类名。

注:该方法的返回值是class类型,而不是String类型。

hashCode()

返回对象的哈希码值。主要是保证基于散列的集合,如HashSet、HashMap以及HashTable等,在插入元素时保证元素不可重复,同时为了提高元素的插入删除便利效率而设计;主要是为了查找的便捷性而存在。

在一次程序运行过程,如果没有修改一个对象的任何信息,则在多次调用对象.hashCode()时,返回的都是相同的整数。如果不是在同一次程序运行过程,则返回的整数不一定相同。

根据equals(Object)方法判断出来的两个对象,如果是相等的话,则其哈希码值也相同;如果两个对象不相等的话,则其哈希码值也不相同。

我们验证一下,基于刚刚的几个类,修改下主函数

public class Main {
    public static void main(String[] args) {
        FirstClass firstClass1=new SecondClass();
        FirstClass firstClass2=new FirstClass();
        FirstClass firstClass11=firstClass1;
        System.out.println(firstClass1.equals(firstClass11)+"-"+firstClass1.hashCode()+"-"+firstClass11.hashCode());
        System.out.println(firstClass1.equals(firstClass2)+"-"+firstClass2.hashCode());
    }
}
           

运行后结果:

JDK1.8源码阅读记录lang包object类JDK1.8源码阅读记录

结果跟我们预想的一样。

equals(Object obj)

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

指示其他某个对象是否“等于”该对象。

由此方法引出“==”运算符,通常情况下,==运算符用于比较基本类型的值是否相同,而equals用于比较两个对象是否相同。

在Object中,equals和==是等价的,只要两个对象的引用相同,则该结果将是true。

在我们自定义对象的时候,一般要重写equals方法。以下是网上找的String中重写的equals方法

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}
           

由于String是引用类型,可能会出现字符串内容相同但引用不相同的情况,因此我们一般比较的是字符串内容是否相等,故在上述方法中,我们先判断引用是否相同,若相同则字符串内容必相同。否则的话,我们再判断变量是否是字符串类型,不是的话则必不相同;是的话则再进一步判断两个字符串的长度以及各个位置上的字符是否一致,若都一致,则判定为两个对象相同。

该方法具有自反性(除了非空对象,自己跟自己比较必相同)、对称性(若没有非空对象,无论谁调用该方法比较另一个对象,结果不变)、传递性(x跟y比较true,y跟z比较true,则x跟z比较同样是true)、一致性(在不改变对象a跟b的情况下,对象a多次调用该方法比较对象b,结果不变)

注:非空对象调用该方法会抛出异常,因此我们一般建议由非空的对象调用该方法比较未知对象。

clone()

顾名思义,该方法是复制对象的作用,用来创建一个与源对象相同的对象。

使用clone复制一个对象,即分配与源对象相同的内存,再用源对象对应的各个域,填充到新对象的域中,最后返回新对象。

同样,创建对象还有new操作符可以进行。运行new操作符时,根据new操作符后面的类型,分配对应的内存空间,再调用构造函数,填充新对象的各个域,即初始化。

在上面的例子中,

FirstClass firstClass1=new SecondClass();
FirstClass firstClass2=new FirstClass();
FirstClass firstClass11=firstClass1;
           

通过new,创建对象。每一次new,都会在栈区多一个引用,在堆区多一个对象,该引用指向该对象。

通过= ,在栈区复制了引用,新引用指向了源引用指向的对象,即firstClass11与firstClass1指向相同的对象。前后变化的只有在栈区多了一个新引用。

而clone方法,也是在栈区多一个引用,在堆区多一个对象,该引用指向该对象。与new不同的是,新对象的内容跟源对象的内容相同。

toString()

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

toString方法,默认返回的String是类名加上‘@’符号加上16进制无符号整数形式返回此哈希码的字符串表示形式。

直接输出对象和使用toString是一样的。

public class Main {
    public static void main(String[] args) {
        FirstClass firstClass1=new SecondClass();
        System.out.println(firstClass1.getClass());
        System.out.println(firstClass1+"\n"+firstClass1.toString());
    }
}
           

结果:

JDK1.8源码阅读记录lang包object类JDK1.8源码阅读记录

finalize()

finalize用于垃圾回收,主要由JVM调用。

小结

关于Object类的源码阅读先做到这里,至于还有几个方法:**notify()/notifyAll()/wait()**等到多线程时我们在来做分析。

finalize()

finalize用于垃圾回收,主要由JVM调用。

小结

关于Object类的源码阅读先做到这里,至于还有几个方法:**notify()/notifyAll()/wait()**等到多线程时我们在来做分析。

这是本人第一篇博客,如有错误之处,还望指出,感谢阅读,2020年2月27日 15:43:36,写这篇博客花费1个半小时,还望本人再接再厉,更近一层楼!

转载请注明:【麻辣西瓜zero的博客】