public final native Class<?> getClass()java
public native int hashCode()app
public boolean equals(Object obj)ide
protected native Object clone() throws CloneNotSupportedExceptionoop
public String toString()性能
public final native void notify()測試
public final native void notifyAll()this
public final native void wait(long timeout) throws InterruptedException線程
public final void wait(long timeout, int nanos) throws InterruptedExceptioncode
public final void wait() throws InterruptedExceptionorm
protected void finalize() throws Throwable
getClass方法是一個final方法,不容許子類重寫,而且也是一個native方法。
返回當前運行時對象的Class對象,注意這裏是運行時,好比如下代碼中n是一個Number類型的實例,可是java中數值默認是Integer類型,因此getClass方法返回的是java.lang.Integer:
Number n = 0; Class<? extends Number> c = n.getClass(); // class java.lang.Integer
hashCode方法也是一個native方法。
該方法返回對象的哈希碼,主要使用在哈希表中,好比JDK中的HashMap。
哈希碼的通用約定以下:
在java程序執行過程當中,在一個對象沒有被改變的前提下,不管這個對象被調用多少次,hashCode方法都會返回相同的整數值。對象的哈希碼沒有必要在不一樣的程序中保持相同的值。
若是2個對象使用equals方法進行比較而且相同的話,那麼這2個對象的hashCode方法的值也必須相等。 若是根據equals方法,獲得兩個對象不相等,那麼這2個對象的hashCode值不須要必須不相同。可是,不相等的對象的hashCode值不一樣的話能夠提升哈希表的性能。
一般狀況下,不一樣的對象產生的哈希碼是不一樣的。默認狀況下,對象的哈希碼是經過將該對象的內部地址轉換成一個整數來實現的。
若是2個對象的equals方法相等,那麼他們的hashCode值也必須相等,反之,若是2個對象hashCode值相等,可是equals不相等,這樣會影響性能,因此仍是建議2個方法都一塊兒重寫。
比較兩個對象是否相等。Object類的默認實現,即比較2個對象的內存地址是否相等:
public boolean equals(Object obj) { return (this == obj); }
建立並返回當前對象的一份拷貝。通常狀況下,對於任何對象 x,表達式 x.clone() != x 爲true,x.clone().getClass() == x.getClass() 也爲true。
Object類的clone方法是一個protected的native方法。
因爲Object自己沒有實現Cloneable接口,因此不重寫clone方法而且進行調用的話會發生CloneNotSupportedException異常。
Object對象的默認實現,即輸出類的名字@實例的哈希碼的16進制:
public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
toString方法的結果應該是一個簡明但易於讀懂的字符串。建議Object全部的子類都重寫這個方法。
**notify方法是一個native方法,而且也是final的,不容許子類重寫。 **
notify方法只能被做爲此對象監視器的全部者的線程來調用。一個線程要想成爲對象監視器的全部者,可使用如下3種方法:
執行對象的同步實例方法 使用synchronized內置鎖 對於Class類型的對象,執行同步靜態方法 一次只能有一個線程擁有對象的監視器。
若是當前線程不是此對象監視器的全部者的話會拋出IllegalMonitorStateException異常
注意點:
由於notify只能在擁有對象監視器的全部者線程中調用,不然會拋出IllegalMonitorStateException異常
跟notify同樣,惟一的區別就是會喚醒在此對象監視器上等待的全部線程,而不是一個線程。
一樣,若是當前線程不是對象監視器的全部者,那麼調用notifyAll一樣會發生IllegalMonitorStateException異常。
wait(long timeout)方法一樣是一個native方法,而且也是final的,不容許子類重寫。
wait方法會讓當前線程等待直到另一個線程調用對象的notify或notifyAll方法,或者超過參數設置的timeout超時時間。
跟notify和notifyAll方法同樣,當前線程必須是此對象的監視器全部者,不然仍是會發生IllegalMonitorStateException異常。
wait方法會讓當前線程(咱們先叫作線程T)將其自身放置在對象的等待集中,而且放棄該對象上的全部同步要求。出於線程調度目的,線程T是不可用並處於休眠狀態,直到發生如下四件事中的任意一件:
其餘某個線程調用此對象的notify方法,而且線程T碰巧被任選爲被喚醒的線程
其餘某個線程調用此對象的notifyAll方法
其餘某個線程調用Thread.interrupt方法中斷線程T
時間到了參數設置的超時時間。若是timeout參數爲0,則不會超時,會一直進行等待
因此能夠理解wait方法至關於放棄了當前線程對對象監視器的全部者(也就是說釋放了對象的鎖)
以後,線程T會被等待集中被移除,而且從新進行線程調度。而後,該線程以常規方式與其餘線程競爭,以得到在該對象上同步的權利;一旦得到對該對象的控制權,該對象上的全部其同步聲明都將被恢復到之前的狀態,這就是調用wait方法時的狀況。而後,線程T從wait方法的調用中返回。因此,從wait方法返回時,該對象和線程T的同步狀態與調用wait方法時的狀況徹底相同。
在沒有被通知、中斷或超時的狀況下,線程還能夠喚醒一個所謂的虛假喚醒 (spurious wakeup)。雖然這種狀況在實踐中不多發生,可是應用程序必須經過如下方式防止其發生,即對應該致使該線程被提醒的條件進行測試,若是不知足該條件,則繼續等待。換句話說,等待應老是發生在循環中,以下面的示例:
synchronized (obj) { while (<condition does not hold>) obj.wait(timeout); ... // Perform action appropriate to condition }``` 若是當前線程在等待以前或在等待時被任何線程中斷,則會拋出InterruptedException異常。在按上述形式恢復此對象的鎖定狀態時纔會拋出此異常。 ### wait(long timeout, int nanos) throws InterruptedException方法 跟wait(long timeout)方法相似,多了一個nanos參數,這個參數表示額外時間(以毫微秒爲單位,範圍是 0-999999)。 因此超時的時間還須要加上nanos毫秒。 須要注意的是 wait(0, 0)和wait(0)效果是同樣的,即一直等待。 ### wait() throws InterruptedException方法 跟以前的2個wait方法同樣,只不過該方法一直等待,沒有超時時間這個概念。 如下這段代碼直接調用wait方法會發生IllegalMonitorStateException異常,這是由於調用wait方法須要當前線程是對象監視器的全部者:
Factory factory = new Factory(); factory.wait();
通常狀況下,wait方法和notify方法會一塊兒使用的,wait方法阻塞當前線程,notify方法喚醒當前線程,一個使用wait和notify方法的生產者消費者例子代碼以下:
public class WaitNotifyTest {
public static void main(String[] args) { Factory factory = new Factory(); new Thread(new Producer(factory, 5)).start(); new Thread(new Producer(factory, 5)).start(); new Thread(new Producer(factory, 20)).start(); new Thread(new Producer(factory, 30)).start(); new Thread(new Consumer(factory, 10)).start(); new Thread(new Consumer(factory, 20)).start(); new Thread(new Consumer(factory, 5)).start(); new Thread(new Consumer(factory, 5)).start(); new Thread(new Consumer(factory, 20)).start(); }
}
class Factory {
public static final Integer MAX_NUM = 50; private int currentNum = 0; public void consume(int num) throws InterruptedException { synchronized (this) { while(currentNum - num < 0) { this.wait(); } currentNum -= num; System.out.println("consume " + num + ", left: " + currentNum); this.notifyAll(); } } public void produce(int num) throws InterruptedException { synchronized (this) { while(currentNum + num > MAX_NUM) { this.wait(); } currentNum += num; System.out.println("produce " + num + ", left: " + currentNum); this.notifyAll(); } }
}
class Producer implements Runnable { private Factory factory; private int num; public Producer(Factory factory, int num) { this.factory = factory; this.num = num; } @Override public void run() { try { factory.produce(num); } catch (InterruptedException e) { e.printStackTrace(); } } }
class Consumer implements Runnable { private Factory factory; private int num; public Consumer(Factory factory, int num) { this.factory = factory; this.num = num; } @Override public void run() { try { factory.consume(num); } catch (InterruptedException e) { e.printStackTrace(); } } }
注意的是Factory類的produce和consume方法都將Factory實例鎖住了,鎖住以後線程就成爲了對象監視器的全部者,而後才能調用wait和notify方法。 輸出:
produce 5, left: 5 produce 20, left: 25 produce 5, left: 30 consume 10, left: 20 produce 30, left: 50 consume 20, left: 30 consume 5, left: 25 consume 5, left: 20 consume 20, left: 0
### finalize方法 finalize方法是一個protected方法,Object類的默認實現是不進行任何操做。 該方法的做用是實例被垃圾回收器回收的時候觸發的操做,就比如 「死前的最後一波掙扎」。 直接寫個弱引用例子:
Car car = new Car(9999, "black"); WeakReference<Car> carWeakReference = new WeakReference<Car>(car);
int i = 0; while(true) { if(carWeakReference.get() != null) { i++; System.out.println("Object is alive for "+i+" loops - "+carWeakReference); } else { System.out.println("Object has been collected."); break; } }
class Car { private double price; private String colour;
public Car(double price, String colour){ this.price = price; this.colour = colour; } // get set method @Override protected void finalize() throws Throwable { System.out.println("i will be destroyed"); }
}
輸出:
.... Object is alive for 26417 loops - java.lang.ref.WeakReference@7c2f1622 Object is alive for 26418 loops - java.lang.ref.WeakReference@7c2f1622 Object is alive for 26419 loops - java.lang.ref.WeakReference@7c2f1622 Object is alive for 26420 loops - java.lang.ref.WeakReference@7c2f1622 Object is alive for 26421 loops - java.lang.ref.WeakReference@7c2f1622 Object is alive for 26422 loops - java.lang.ref.WeakReference@7c2f1622 Object has been collected. i will be destroyed