1. 意义
为什么今天我想说这个类呢,因为作为the root of class hierarchy,我发现我竟没有认认真真好好理解它的内容以及所有方法的意义。这似乎是不应该的。。。。so,补课,重新学习它
定义:
Object对象是Java类层次结构的根类,所有类的超类
所有的对象(包括数组)都实现这个类的方法
2. 方法
JavaSE7API中的Outline
Object()
构造方法,默认的,没有显示声明
private static native void registerNatives()
private static native void registerNatives(); static { registerNatives(); }
很多类中都有的一段JNI代码,用于统一的将当前类的所有native方法映射到相应的C方法上
比如,这个Object里的这个方法对应的OpenJDK源码(源码相对目录:…\openjdk\jdk\src\share\native\java\lang下)中C代码是
static JNINativeMethod methods[] = { {"hashCode", "()I", (void *)&JVM_IHashCode}, {"wait", "(J)V", (void *)&JVM_MonitorWait}, {"notify", "()V", (void *)&JVM_MonitorNotify}, {"notifyAll", "()V", (void *)&JVM_MonitorNotifyAll}, {"clone", "()Ljava/lang/Object;", (void *)&JVM_Clone}, }; JNIEXPORT void JNICALL Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls) { (*env)->RegisterNatives(env, cls, methods, sizeof(methods)/sizeof(methods[0])); } JNIEXPORT jclass JNICALL Java_java_lang_Object_getClass(JNIEnv *env, jobject this) { if (this == NULL) { JNU_ThrowNullPointerException(env, NULL); return 0; } else { return (*env)->GetObjectClass(env, this); } }
可以看到,这里映射了5个具体的native方法:hashCode、wait、notify、notifyAll、clone和实现了一个方法getClass
public final native Class<?> getClass()
不可被覆盖的final方法,其返回的是当前内存中的被引用的实际对象的class,而不是字面上看上去的对象的class
例如,最常见的一道面试题会这样问:
super.getClass().getName(); //返回的是什么? // 答案并非父类的名字,而是当前this对象的class对象的名字 //而要获取父类的名字可以如下 getClass().getSuperClass().getName();
public native int hashCode()
返回当前对象的hash code,这个方法用于提高hash表们的性能(例如java.util.Hashtable提供的hash表)
这个方法的general contract是:
- 同一个对象多此调用hashCode()必须返回相同的整数,前提是对象的equals()方法用到的信息没有被修改
- 如果根据equals()方法,两个对象是相等的,那么hashCode必须返回相同的整数
- 如果根据equals()方法,两个对象不相等,那么也有可能hashCode相等
这个
public boolean equals(Object obj)
public boolean equals(Object obj) { return (this == obj); }
equals方法指示对象是否“相等”
Object类中这个equals实现的是对象上差别可能性最大的相等关系,即,对于非空引用x和y,仅当其引用的是同一个对象时才返回true
equals方法在非空引用上实现相等关系必须满足几个性质:
- 自反性:x..equals(x) 必须为true
- 对称性:y.equals(x)为true,x.equals(y)也应为true
- 传递性:x.equals(y),y.equals(z)那么x.equals(z)也应为true
- 一致性:多此调用equals,结果应该一致,在equals所用信息没有被修改的前提下
- x.equals(null)必须为false
如果重写equals方法,通常有必要重写hashCode方法,用以维护hashCode方法的常规协定,来保证equals的对象必须具有相等的hash code
protected native Object clone() throws CloneNotSupportedException
克隆当前对象生成新的实例
- 被克隆对象必须实现接口 Cloneable
- 所有数组都被看做已经实现了Cloneable
- 这个clone是“浅表 copy”而不是“deep copy”
shallow copy就是说没有clone源对象的引用成员变量所指向的对象,而是直接使用了源对象的引用
一道面试题:怎么(浅表copy)clone对象?clone()方法通常都有一行代码,是什么?
答案:
实现Cloneable接口并override重写clone()方法;
super.clone(),按照惯例克隆对象必须通过super.clone()来完成代码:
class A implements Cloneable{ public Object clone() throws CloneNotSupportedException { A cloned = (A) super.clone(); //cloned.xxx引用成员 = (B) xxx引用成员.clone() //这是deep clone return cloned; } }
public String toString()
public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
方法返回对象的字符串表示。建议所有子类重写此方法
Object类默认的toString()返回一个字符串,值为:
getClass().getName() + "@" + Integer.toHexString(hashCode());
public final native void notify()
唤醒在此对象监视器上waiting的单个线程。如果有很多线程都在此对象上waiting,则会任意选择一个唤醒。线程通过调用wait方法,使自己处于waiting状态
被唤醒的线程将以常规的方式与其它在该对象上同步的所有线程进行竞争
notify()方法只能被对象监视器当前所有者线程来调用,一次只能有一个线程拥有对象的监视器。有3种方法,线程可以称为对象监视器的拥有者:
- 执行对象的synchronized实例方法
- 执行对象的synchronized语句
- 对于Class类型的对象,可以执行类的synchronized静态方法
public final native void notifyAll()
唤醒在此对象监视器上waiting的所有线程,其它参考notify
public final native void wait(long timeout) throws InterruptedException
使当前线程waiting并进入当前对象监视器的wati set中,直到超出timeout或notify被调用
注意:
调用对象的wait()类方法时,对象必须拥有对象监视器的锁,如果没有将抛出异常“IllegalMonitorStateException”。也就是说必须在synchronized语句块中调用(或java.util.concurrent包中类);另外:
调用wait(0),相当于调用wait()会一直被wait
11和12最终还是调用10这个方法public final void wait(long timeout, int nanos) throws InterruptedException
纳秒级别控制wait时间
最终还是调用
wait(timeout);
public final void wait() throws InterruptedException
public final void wait() throws InterruptedException { wait(0); }
protected void finalize() throws Throwable { }
当GC确定不存在该对象的更多引用,想要清楚此对象时,GC会调用该方法。子类重写此方法,以处置系统资源或执行其它清除
你当然可以在GC将要回收时,在finalize方法中重新使此对象对其它线程可用(救下它),但是,finalize()方法的主要目的是:在不可撤销(前面说的操作叫撤销)的要丢弃对象的情况下,给你一个机会让你去执行一些清除操作。例如,输入/输出连接的相关对象的finalize方法可以显示的执行I/O事务,以便在丢弃对象前中断连接
- finalize被执行后,对象不会立马被丢弃,JVM会再次确定一遍,如果还是“不可达”,才会真正丢弃
- 对于一个对象,JVM最多只会调用一次finalize方法