一、Object中所有方法简介:
在根类Object中包含一下方法:
- clone();
- equals();
- finalize();
- getClass();[align=left][/align]
- notify(),notifyAll();
- hashCode();
- toString();
- wait();
首先大家要明白回调(callback)方法,所谓回调方法就是程序在运行特定功能时JVM会自动调动这些方法,假设你使用System.out.print(obj)打印出对象obj信息,则运行时JVM会自动调用obj对象的toString()方法,toString()方法就是回调方法。理解回调方法后,下面我们来看这些方法:
- clone():clone方法主要用于克隆当前对象,制作本地对象,这肯定需要在所有对象中所拥有,在讲解参数按值传递和按引用传递时再讲解它的用法;但clone()在Object中protected方法,所以子类实现需要覆盖此方法并实现Cloneable接口,那样才能在外部实现clone功能equals()、toString()和hashCode():这两个方法主要用于比较两个对象是否相等,查看Object源代码(要多查看源代码便于自己理解)知道,默认的equals()是:
- boolean equals(Object obj){
- return this == obj;
- }
==只有当两个对象地址相同时才返回true,所以默认的equals()方法根本没什么用,因为对象在内存中的地址(基本类型不同)肯定不同的;所以我们编写类时最好覆盖默认的equals()、hashCode()和toString()方法(查看JDK中的类也大部分覆盖了这些方法),
hashCode():默认的hashCode()返回的值就是对象在内存中的地址。
toString():而默认的toString()方法就是打印出对象的地址。
toString()和equals()方法内部是通过hashCode()的返回值来实现的,hashCode()是本地(native)方法,所谓本地方法就是使用其他语言(C或C++)编写的,我们可以通过本地接口(JNI)编写本地方法;
- finalize():这是GC清理对象之前所调用的清理方法,是回调方法,我们可以覆盖这个方法写一些清理的代码,GC会自动扫描没有引用的对象,即对象赋值为null;可以通过调用System.runFinalization()或System.runFinalizersOnExit()强制GC清理该对象前调用finalize()方法,GC有时不会调用对象的finalize()方法(由JVM决定);
- getClass():返回当前对象的Class类的对象引用,用于取得类名等(方法查看API);
- notify()、notifyAll()和wait():这三个方法主要用于多线程中。
- wait():执行了该方法的线程释放对象的锁,JVM会把该线程放到对象的等待池中。该线程等待其它线程唤醒
- notify():执行该方法的线程唤醒在对象的等待池中等待的一个线程,JVM从对象的等待池中随机选择一个线程,把它转到对象的锁池中。
通常可以使用synchronized和notify,notifyAll以及wait方法来实现线程之间的数据传递及控制。对于对象obj来说:
- obj.wait():该方法的调用,使得调用该方法的执行线程(T1)放弃obj的对象锁并阻塞,直到别的线程调用了obj的notifyAll方法、或者别的线程调用了obj的notify方法且JVM选择唤醒(T1),被唤醒的线程(T1)依旧阻塞在wait方法中,与其它的线程一起争夺obj的对象锁,直到它再次获得了obj的对象锁之后,才能从wait方法中返回。(除了notify方法,wait还有带有时间参数的版本,在等待了超过所设时间之后,T1线程一样会被唤醒,进入到争夺obj对象锁的行列;另外中断可以直接跳出wait方法)
- obj.notify():该方法的调用,会从所有正在等待obj对象锁的线程中,唤醒其中的一个(选择算法依赖于不同实现),被唤醒的线程此时加入到了obj对象锁的争夺之中,然而该notify方法的执行线程此时并未释放obj的对象锁,而是离开synchronized代码块时释放。因此在notify方法之后,synchronized代码块结束之前,所有其他被唤醒的,等待obj对象锁的线程依旧被阻塞。
- obj.notifyAll():与notify的区别是,该方法会唤醒所有正在等待obj对象锁的线程。(不过同一时刻,也只有一个线程可以拥有obj的对象锁)
举例:
int nsize=5;
synchronized(obj){
if(nsize>=5){
nsize--;
obj.wait(); //该句执行后,当前线程阻塞,后面代码不会执行
}
nsize++;
obj.notify(); //释放当前对象锁
}
上述代码使得nszie始终会小于等于5,超过5时自动阻塞。二、几种常用方法详解
1. equals方法
Object类中的equals方法用于检测一个对象是否等于另一个对象,具体是比较两个对象是否具有相同的引用。这一点与“==”具有相同的功效。即是说,对于除开String对象的其他对象,equals与 == 具有一样的效果。而java.lang.String重写了equals方法,下面对这一点细说。
Object类中:
可以看出,equals判断实际上进行的就是 == 判读。public boolean equals(Object obj) { return (this == obj); }
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = count; if (n == anotherString.count) { char v1[] = value; char v2[] = anotherString.value; int i = offset; int j = anotherString.offset; while (n-- != 0) { if (v1[i++] != v2[j++]) return false; } return true; } } return false; }
散列码(hash code)是由对象导出的一个整型值。散列码是没有规律的,如果x和y是两个不同的对象,那x.hashCode()与y.hashCode()一般是不相同的。
String类使用以下算法计算散列码:
public int hashCode() { int h = hash; if (h == 0) { int off = offset; char val[] = value; int len = count; for (int i = 0; i < len; i++) { h = 31*h + val[off++]; } hash = h; } return h; }
即是说,String类的散列码是由内容导出的。如果两个String对象的内容相同,它们的散列码也相同。
而Object中,每个对象都有一个默认的散列码,其值为对象的存储地址。
equals若返回的是true,则对象的散列码必须一致。
3. toString方法
Object类定义了toString方法,打印输出对象所属的类名和散列码。
只要一个对象与一个字符串通过操作符“+”连接起来,Java编译就会自动的调用toString方法,以便获得这个对象的字符串描述。public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
Point p = new Point ( 10, 20 ) ; String message = "The current position is " + p ; //调用p.toStr