Object
JAVA中Object是所有类的超类,也就是说一切对象都是继承自Object类。我们从这里迈入JDK源码的大门。
Object中的方法一览
private static native void registerNatives();
public final native Class<?> getClass();
public native int hashCode();
public boolean equals(Object obj);
protected native Object clone() throws CloneNotSupportedException;
public String toString();
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;
public final void wait() throws InterruptedException;
protected void finalize() throws Throwable;
registerNatives()
我们可以发现这个方法使用了native
进行修饰,这表明这是一个本地方法,所谓的本地方法是不通过Java语言实现的方法,但可以通过JNI像调用Java方法一样调用这些方法。底层是使用C、C++来实现的,我们可以通过查看OpenJDK查看底层源码:
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]));
}
这部分代码实现对本地方法的注册(即初始化java方法映射到C的方法)。具体的知识请学习JNI。
getClass()
返回运行时对象的Class。在反射中经常使用。
hashCode()
返回对象的哈希码值。hashCode()方法在hash table和hash map等容器中尤为重要。使用hashCode()方法判断Key是否相同(事实上没那么简单,涉及解决冲突),或者迅速找到对应的元素。
hashCode方法的约定:
- 在应用程序执行期间,只要对象的equals方法的比较操作所用到的信息没有被修改,那么对这同一个对象调用多次,hashCode方法都必须始终如一的返回同一个整数。在同一个应用程序的多次执行过程中,每次执行所返回的整数可以不一致。
- 如果两个对象根据equals()方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode方法都必须产生同样的整数结果。
- 如果两个对象根据equals(Object)方法比较是不相等的,那么调用这两个对象中任意一个对象的hashCode方法,则不一定要产生不同的整数结果。(尽管如此,理想的hashCode方法对不相等的对象,应当提供不同的hashCode值,这样当我们将对象作为Map的key时,可以提高散列表的性能)
一般情况下子类都会重写hashCode()方法,比如String类的hashCode()方法如下:
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
可以发现空串的哈希码为0。
equals()
返回 2个对象的内存地址是否相等。在Object中的实现为:
public boolean equals(Object obj) {
return (this == obj);
}
==表示的是变量值完成相同(对于基础类型,地址中存储的是值,引用类型则存储指向实际对象的地址)。默认equals()方法比较obj的地址是否等于自身地址。大部分情况下我们使用equals()比较的不仅仅判断地址是否相同,更应该判断对象中的内容是否相同。比如String类比较每个字符是否相同。
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
首先判断地址是否相同,地址相同就是一个对象嘛!如果地址不同,逐一判断每个字符是否相同。
equals方法的通用约定:
- 自反性:对于任何非null的引用值x,x.equals(x)必须返回true。
- 对称性:对于任何非null的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)必须返回true。
- 传递性:对于任何非null的引用值x、y、z,如果x.equals(y)返回true,并且y.equals(z)返回true,那么x.equals(z)也必须返回ture。
- 一致性:对于任何非null的引用值x和y,只要equals的比较操作在对象中所用的信息没有被修改,多次调用x.equals(y)就会一致的返回ture,或者一致的返回false。
- 非空性:对于任何非null的引用值x,x.equals(null)必须返回false。
注意:当我们覆盖了equals方法时,一定不能忘记覆盖hashCode方法
clone()
创建并且返回对象的拷贝。对象重写clone()方法必须实现Cloneable接口,否则抛出java.lang.CloneNotSupportedException
。注意:使用clone()时需要注意深拷贝和浅拷贝的问题。
toString()
默认返回:getClass().getName() + "@" + Integer.toHexString(hashCode());
当打印对象时会自动调用toString()方法。为了打印美观我们一般都会自己实现此方法。
finalize()
垃圾回收器准备释放内存的时候,会先调用finalize()。对于任何给定对象,Java 虚拟机最多只调用一次finalize方法。我们需要注意的是GC时不一定马上调用此方法。大部分情况下不建议使用finalize()方法。
wait()
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException;
public final void wait() throws InterruptedException;
wait()方法是不允许重写的。
当线程调用wait()方法时,释放锁,进入阻塞状态,等待被唤醒。
wait()
:当前线程阻塞,直到被唤醒。wait(long time)
:当前线程阻塞,直到其他线程调用此对象的notify()
方法或notifyAll()
或超过设定时间wait(long timeout, int nanos)
:当前线程阻塞导致当前的线程等待,直到其他线程调用此对象的notify()
方法或notifyAll()
方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。
notify()
唤醒在此对象监视器上等待的单个线程。
notifyAll()
唤醒在此对象监视器上等待的所有线程。
关于这几个多线程方法以后会再次接触,此处只是简单了解作用。
版权属于:带翅膀的猫
本文链接:https://www.chengpengper.cn/archives/28/
转载时须注明出处及本声明