Java 是一门面向对象的语言,在 Java 里面一切均可以看做是一个对象,而 Java 里面全部的对象都默认继承于 Object 类,因此狗哥今天就复习了一遍这个类。java
上图看出 Object 一共有 12 个方法,其中 registerNatives() 是由 C 语言实现的,这个不在研究范围内。bash
/**
* Returns the runtime class of this {@code Object}. The returned
* {@code Class} object is the object that is locked by {@code
* static synchronized} methods of the represented class.
*/
public final native Class<?> getClass();
复制代码
这个方法的做用就是返回某个对象的运行时类,它的返回值是 Class 类型,Class c = obj.getClass();经过对象 c ,咱们能够获取该对象的全部成员方法,每一个成员方法都是一个 Method 对象;咱们也能够获取该对象的全部成员变量,每一个成员变量都是一个 Field 对象;一样的,咱们也能够获取该对象的构造函数,构造函数则是一个 Constructor 对象。这个方法在反射时会经常使用到。ide
/**
* Returns a hash code value for the object. This method is
* supported for the benefit of hash tables such as those provided by
* {@link java.util.HashMap}.
*/
public native int hashCode();
复制代码
这个方法的注释比较长,就不放出来了。注释指出:函数
public boolean equals(Object obj) {
return (this == obj);
}
复制代码
equals 的实现很是简单,它的做用就是比较两个对象是否相等,而比较的依据就是两者的内存地址。除此以外,equals 还遵循如下几个原则:ui
一、自反性:x.equals(x); // true
二、对称性:x.equals(y) == y.equals(x); // true
三、传递性:if (x.equals(y) && y.equals(z))
x.equals(z); // true;
四、一致性,只要对象没有被修改,屡次调用 equals() 方法结果不变:
x.equals(y) == x.equals(y); // true
五、非空性,对任何不是 null 的对象 x 调用 x.equals(null) 结果都为 false :
x.equals(null); // false;
复制代码
为何要重写 hashcode 和 equals ?this
这个问题以前分享过旧文:mp.weixin.qq.com/s/iIoAnneae…spa
protected native Object clone() throws CloneNotSupportedException;
复制代码
clone() 是 Object 的 protected 方法,它不是 public,一个类不显式去重写 clone(),其它类就不能直接去调用该类实例的 clone() 方法。此外,Clone 的注释中还提到比较重要的几点:.net
关于浅拷贝与深拷贝的详解,请看这篇旧文: mp.weixin.qq.com/s/I6Gq1shyf…线程
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
复制代码
这个方法应该没什么好讲的,原生的 toString 方法仅仅返回,对象名 + 它的 hashCode ,但作过开发的都知道,原生的 toString 做用不大。咱们须要重写 toString 通常是由于方便调试,须要知道对象的属性值,而不只仅是 hashCode 。因此,应该像下面这样重写:3d
public class Student {
private int age;
private String name;
// 省略 get、set
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' + '}'; } } 复制代码
public final native void notify();
public final native void notifyAll();
复制代码
首先是 notify ,注释就不贴出来了,notify 的做用就是随机唤醒在等待队列的某个线程,而 notifyAll 就是唤醒在等待队列的全部线程。
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 的做用是让当前线程进入等待状态,同时,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) 效果同样。
除此以外,notify 和 wait 的注释中还有这么一段:
* <p>
* This method should only be called by a thread that is the owner
* of this object's monitor. A thread becomes the owner of the * object's monitor in one of three ways:
* <ul>
* <li>By executing a synchronized instance method of that object.
* <li>By executing the body of a {@code synchronized} statement
* that synchronizes on the object.
* <li>For objects of type {@code Class,} by executing a
* synchronized static method of that class.
* </ul>
* <p>
复制代码
看到这英文,刚过四级的我瑟瑟发抖。以上注释主要就是描述了,notify 和 wait 方法的使用规范。意思就是这两者必须在 synchronized 修饰的同步方法或同步代码中使用。
答:调用 wait() 就是释放锁,释放锁的前提是必需要先得到锁,先得到锁才能释放锁。
答:notify()、notifyAll() 是将锁交给含有 wait() 方法的线程,让其继续执行下去,若是自身没有锁,怎么叫把锁交给其余线程呢?(本质是让处于入口队列的线程竞争锁)
详细解释请参考这篇博文:blog.csdn.net/qq_42145871…
首先,两者均可以暂停当前线程,释放 CPU 控制权。主要的区别在于 Object.wait()在释放 CPU 同时,释放了对象锁的控制。而 Thread.sleep() 没有对锁释放。换句话说 sleep 就是耍流氓,占着茅坑不拉屎。
推荐阅读: