前言
Java 是一门面向对象的语言,在 Java 里面一切都可以看作是一个对象,而 Java 里面所有的对象都默认继承于 Object 类。
本文基于JDK1.8
可以看到一共12个方法,其中 registerNatives() 是 native 修饰的,一个本地方法,具体是用C(C++)在DLL中实现的,然后通过JNI调用。
getClass
- public final native Class getClass();
getClass 也是个 native 方法,这个方法的作用就是返回某个对象的运行时类,它的返回值是 Class 类型,Class c = obj.getClass();通过对象 c ,我们可以获取该对象的所有成员方法,每个成员方法都是一个 Method 对象;我们也可以获取该对象的所有成员变量,每个成员变量都是一个 Field 对象;同样的,我们也可以获取该对象的构造函数,构造函数则是一个 Constructor 对象。这个方法在反射时会常用到。
hashCode
- public native int hashCode();
- hashCode 方法返回散列值。
- 返回值默认是由对象的地址转换而来的。
- 同一个对象调用 hashCode 的返回值是相等的。
- 两个对象的 equals 相等,那 hashCode 一定相等。
- 两个对象的 equals 不相等,那 hashCode 也不一定相等。
equals
- public boolean equals(Object obj) {
- return (this == obj);
- }
equals 的实现非常简单,它的作用就是比较两个对象是否相等,而比较的依据就是二者的内存地址。除此之外,equals 还遵循以下几个原则:
- 1、自反性:x.equals(x); // true
- 2、对称性:x.equals(y) == y.equals(x); // true
- 3、传递性:if (x.equals(y) && y.equals(z))
- x.equals(z); // true;
- 4、一致性,只要对象没有被修改,多次调用 equals() 方法结果不变:
- x.equals(y) == x.equals(y); // true
- 5、非空性,对任何不是 null 的对象 x 调用 x.equals(null) 结果都为 false :
- x.equals(null); // false;
为什么要重写 hashcode 和 equals ?
因为这两个方法都跟对象的比较有关,所以如果在程序中要做对象比较,那大概率要重写这两个方法了。因为equals默认的比较逻辑就是对象的地址进行比较,两个对象内存地址肯定不同,所以无论如何两个对象通过eqals比较肯定返回false。
但在实际编程中,我们经常会遇到去重,或者将对象放到有序集合中,或者将对象存入无重复的集合中,这时如果没有重写equals和hashCode,则无法达到需求。
举个例子,系统中同时存在两个对象,对象A和对象B,其姓名和身份证号一模一样。此时,在系统内存中是两个对象,但其内容一致分明是一个人同时产生了两条重复信息。如果使用默认的equals方法比较,则这两个对象永远不相等,永远不能比出来是一条相同的重复信息。所以,要重写equals和hashCode方法来达到以上需求效果。
clone
- protected native Object clone() throws CloneNotSupportedException;
clone() 是 Object 的 protected 方法,它不是 public,一个类不显式去重写 clone(),其它类就不能直接去调用该类实例的 clone() 方法。此外,Clone 的注释中还提到比较重要的几点:
- 克隆的对象必须要实现 Cloneable 接口并重写 clone 方法,否则会报 CloneNotSupportedException 异常
- clone() 方法并不是 Cloneable 接口的方法,而是 Object 的一个 protected 方法。Cloneable 接口只是规定,如果一个类没有实现 Cloneable 接口又调用了 clone() 方法,就会抛出 CloneNotSupportedException。
- 浅拷贝:拷贝对象和原始对象的引用类型引用同一个对象。
- 深拷贝:拷贝对象和原始对象的引用类型引用不同对象。
关于浅拷贝与深拷贝我们后面再讨论。
toString
- public String toString() {
- return getClass().getName() + "@" + Integer.toHexString(hashCode());
- }
返回该对象的字符串表示,非常重要的方法
- getClass().getName(); 获取字节码文件的对应全路径名例如java.lang.Object;
- Integer.toHexString(hashCode()); 将哈希值转成16进制数格式的字符串。
wait 和 notify
- public final void wait() throws InterruptedException {
- wait(0);
- }
-
- public final native void wait(long timeout) throws InterruptedException;
-
- public final void wait(long timeout, int nanos) throws InterruptedException {
- if (timeout < 0) {
- throw new IllegalArgumentException("timeout value is negative");
- }
-
- if (nanos < 0 || nanos > 999999) {
- throw new IllegalArgumentException(
- "nanosecond timeout value out of range");
- }
-
- if (nanos > 0) {
- timeout++;
- }
-
- wait(timeout);
- }
wait 的作用是让当前线程进入等待状态,同时,wait() 也会让当前线程释放它所持有的锁。直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,当前线程被唤醒进入就绪状态。
wait(long timeout) (以毫秒为单位)让当前线程处于等待(阻塞)状态,直到其他线程调用此对象的notify() 方法或 notifyAll() 方法,或者超过指定的时间量,当前线程被唤醒进入就绪状态。
wait(long timeout, int nanos) 和 wait(long timeout) 功能一样,唯一的区别是这个可以提供更高的精度。总超时时间(以纳秒为单位)计算为 1000000 *timeout+ nanos。By the way ,wait(0,0) 和 wait(0) 效果一样。
- ublic final native void notify();
- public final native void notifyAll();
首先是 notify ,notify 的作用就是随机唤醒在等待队列的某个线程,而 notifyAll 就是唤醒在等待队列的所有线程。
注意:notify 和 wait 方法的使用规范。意思就是这二者必须在 synchronized 修饰的同步方法或同步代码中使用。
Thread.sleep() 和 Object.wait() 有什么区别?
首先,二者都可以暂停当前线程,释放 CPU 控制权。主要的区别在于 Object.wait()在释放 CPU 同时,释放了对象锁的控制。而 Thread.sleep() 没有对锁释放。换句话说 sleep 就是耍流氓,占着茅坑不拉屎。
完整代码
- package java.lang;
-
-
- public class Object {
-
-
- private static native void registerNatives();
-
-
- static {
- registerNatives();
- }
-
-
- public final native Class> getClass();
-
-
- public native int hashCode();
-
-
- public boolean equals(Object obj) {
- return (this == obj);
- }
-
-
- protected native Object clone() throws CloneNotSupportedException;
-
-
- public String toString() {
- return getClass().getName() + "@" + Integer.toHexString(hashCode());
- }
-
-
- public final native void notify();
-
-
- public final native void notifyAll();
-
-
- public final native void wait(long timeout) throws InterruptedException;
-
-
- public final void wait(long timeout, int nanos) throws InterruptedException {
- if (timeout < 0) {
- throw new IllegalArgumentException("timeout value is negative");
- }
-
- if (nanos < 0 || nanos > 999999) {
- throw new IllegalArgumentException(
- "nanosecond timeout value out of range");
- }
-
- if (nanos > 0) {
- timeout++;
- }
-
- wait(timeout);
- }
-
-
- public final void wait() throws InterruptedException {
- wait(0);
- }
-
-
- protected void finalize() throws Throwable {
- }
- }
PS:这里有一个技术交流群(扣扣群:1158819530),方便大家一起交流,持续学习,共同进步,有需要的可以加一下。