今天有空来总结一下Java.lang包中的Object类,如有不当请多指教!
Object类是Java中其他所有类的父类。
Object类位于java.lang包中,java.lang包包含着Java最基础和核心的类,在编译时会自动导入。
Object类没有定义属性,一共有12个方法,具体如下:
registerNatives()
clone()
getClass()
equals(Object obj)
hashCode()
toString()
notify()
notifyAll()
wait()
wait(long timeout)
wait(long timeout, int nanos)
finalize()
接下来我们来对这些方法逐个介绍。
registerNatives
private static native void registerNatives();
static {
registerNatives();
}
registerNatives函数前面有native
关键字修饰,Java中,用native关键字修饰的函数表明该方法的实现并不是在Java中去完成, 而是由C/C++去完成,并被编译成了.dll,由Java去调用。方法的具体实现体在dll文件中,对于不同平台,其具体实现应该有所不同。
clone
protected native Object clone() throws CloneNotSupportedException;
clone函数返回的是一个引用,指向的是新的clone出来的对象,此对象与原对象分别占用不同的堆空间。只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。Cloneable接口仅是一个表示接口,接口本身不包含任何方法。
clone和copy的区别:
假设现在有一个Person对象,Person person1 =new Person("czy",18);通常会有这样的复制
Person person2=person1,这个时候只是简单了copy了一下reference,person1和person2都指向内存中同一个object,这样person1或者person2的一个操作都可能影响到对方。显然这不是我们愿意看到的。我们希望得到tobby的一个精确拷贝,同时两者互不影响,这时候我们就可以使用Clone来满足我们的需求。
Person person2=person1.clone(),这时会生成一个新的Person对象,并且和person1具有相同的属性值和方法。
getClass
public final native Class> getClass();
getClass()也是一个native
方法,返回的是此Object对象的类对象/运行时类对象Class>。效果与Object.class相同。
equals
public boolean equals(Object obj) {
return (this == obj);
}
可以看到Object中的equals方法默认使用==进行比较。
==和equals的区别:
在Java中有8种基本数据类型:
- 浮点型:float(4 byte)
, double(8 byte)
- 整型:byte(1 byte)
, short(2 byte)
, int(4 byte)
, long(8 byte)
- 字符型: char(2 byte)
- 布尔型: boolean
(JVM规范没有明确规定其所占的空间大小,仅规定其只能够取字面值"true"和"false")
对于这8种基本数据类型的变量,变量直接存储的是“值”,因此在用关系操作符==来进行比较时,比较的就是 “值” 本身。
而对于非基本数据类型的变量,引用类型的变量存储的并不是 “值”本身,而是于其关联的对象在内存中的地址。
总结来说:
- 对于==,如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;如果作用于引用类型的变量,则比较的是所指向的对象的地址
- 对于equals方法,如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。
Java中的约定:重写equals()方法必须重写hasCode()方法。
hashcode
public native int hashCode();
hashCode()方法返回一个整形数值,表示该对象的哈希值。
由于hashCode方法定义在Object类,所以每个对象都有一个默认的哈希值,其值为对象的存储地址。
hashCode()具有如下约定:
- 在Java应用程序程序执行期间,对于同一对象多次调用hashCode()方法时,其返回的哈希码是相同的,前提是没有重写equals()方法。
- 如果两个对象相等(依据:调用equals()方法),那么这两个对象调用hashCode()返回的哈希码也必须相等;
- 反之,两个对象调用hasCode()返回的哈希码相等,这两个对象不一定相等。
hashCode()方法主要用于增强哈希表的性能。
以集合类中,以Set为例,当新加一个对象时,需要判断现有集合中是否已经存在与此对象相等的对象。
如果没有hashCode()方法,需要将Set进行一次遍历,并逐一用equals()方法判断两个对象是否相等,此种算法时间复杂度为o(n)。
通过借助于hasCode方法,先计算出即将新加入对象的哈希码,然后根据哈希算法计算出此对象的位置,直接判断此位置上是否已有对象即可。
toString
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
toString()方法返回该对象的字符串表示。
getClass().getName():返回类对象的名称
Integer.toHexString(hashCode()):以对象的哈希码为实参,以16进制无符号整数形式返回此哈希码的字符串表示形式。
toString()是由对象的类型和其哈希码唯一确定,同一类型但不相等的两个对象分别调用toString()方法返回的结果可能相同。
wait/notify/notifyAll
这几个方法主要用于java多线程之间的协作。
在Object类中有三个wait的重载方法:wait() 、wait(long timeout)、wait(long timeout, int nanos)
wait():调用此方法所在的当前线程等待,直到在其他线程上调用此方法的的notify()/notifyAll()方法。
wait(long timeout)/wait(long timeout, int nanos):调用此方法所在的当前线程等待,直到在其他线程上调用此方法的notisfy()/notisfyAll()方法,或超过指定的超时时间。
notify()/notifyAll():唤醒在此对象监视器上等待的随机单个线程/所有线程。
既然是作用于多线程中,为什么却是Object这个基类所具有的方法?
原因在于理论上任何对象都可以视为线程同步中的监听器
,且wait(...)/notify()|notifyAll()方法只能在同步代码块中才能使用。
finalize
protected void finalize() throws Throwable { }
finalize方法主要与Java垃圾回收机制有关。
Object中定义finalize方法表明Java中每一个对象都将具有finalize这种行为, 其具体调用时机在:JVM准备对此对对象所占用的内存空间进行垃圾回收前,将被调用。由此可以看出,此方法并不是由我们主动去调用的。
参考
https://www.cnblogs.com/lwbqqyumidi/p/3693015.html