共计 3232 个字符,预计需要花费 9 分钟才能阅读完成。
今天有空来总结一下 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