Java Object對象相關問題分析

package java.lang;

public class Object {

    private static native void registerNatives();
    static {
        registerNatives();
    }

    // 類加載器
   //返回Object 的運行時類
    public final native Class<?> getClass();

   
    public native int hashCode();

  
    public boolean equals(Object obj) {
        return (this == obj);
    }

   
    protected native Object clone() throws CloneNotSupportedException;

  
    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

  
    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 {
        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 >= 500000 || (nanos != 0 && timeout == 0)) {
            timeout++;
        }

        wait(timeout);
    }

  
    public final void wait() throws InterruptedException {
        wait(0);
    }

    protected void finalize() throws Throwable { }
}

爲什麼不用繼承Object對象,就可以擁有Object的方法,虛擬機做了什麼

JVM在編譯源代碼時,在遇到沒有繼承Object的對象的時候,編譯器會默認指定一個默認的父類Object

Object 和接口的關係,接口是否繼承Object

接口沒有繼承頂級父類,會隱式的聲明一套和Object中的方法簽名完全一樣的方法,這也就符合萬物皆對象的面向對象思想,任何對象直接或間接的跟Object對象有關

1. getClass()方法,返回的是運行時類Class,也就是當前運行類的字節碼對象,可以獲取到構造器、屬性、方法

Java中獲取Class對象的方式:

a.通過類名的方式 ClassName.class 編譯期,不能執行到靜態信息和動態信息

b.通過Class的方法中,使用類的全路徑方式 Class.forName("類路徑名"); 運行時期,可以執行到靜態信息,不能獲取到動態信息

c.通過運行實例類過去 Object.getClass(); 運行時期,可以到所有的信息

 

它們獲取到的Class字節碼對象的區別?

 

Classd對象和實例對象的關係?(https://blog.csdn.net/javazejian/article/details/70768369?utm_source=gold_browser_extension

 

過去到Class,跟反射相關。

 

2.重寫equals()方法,爲什麼也需要重寫hashcode()方法

對象判斷相當obj==obj1;

equals(Object obj){

this==obj;

}

 

如果重寫了equals方法,沒有重寫hashCode()方法;

會出現equals()相等爲true; 而obj==obj1是對象判斷,取出的是對象散列值,所以爲false。所以顯然沒有達到想要的效果,需要得到這個對象也相等


 

        public final boolean equals(Object o) {
           if (!(o instanceof Map.Entry))
                return false;
            Map.Entry e = (Map.Entry)o;
            Object k1 = getKey();
            Object k2 = e.getKey();
            if (k1 == k2 || (k1 != null && k1.equals(k2))) {
                Object v1 = getValue();
                Object v2 = e.getValue();
                if (v1 == v2 || (v1 != null && v1.equals(v2)))
                    return true;
            }
            return false;
        }

        public final int hashCode() {
            return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
        }

 

3. hashcode()算法 javaHashCode算法是通過存儲地址值和對象信息算出來的

String,Long,Double,HashMap等對象都重寫了hashCode()方法和equals()方法,爲了比較的對象和數值有關

Integer 返回原來的value值

 

Hash衝突的解決方案:

1.鏈表的方式:

2.再哈希方法:當發現衝突的時候,再次計算hash值來得到

3.開放地址:線性探測再散列,二次探測再散列,僞隨機探測再散列

4.建立公共溢出區

 

Long、Double重寫HashCode算法

    public int hashCode() {
        return (int)(value ^ (value >>> 32));
    }

 

Long,Double重寫hashCode() 做右移32位的原因?

爲了避免高32位相同、低32位不同hashCode()生成的key一樣,推薦的做法是將高32位和低32位做異或運算,

id >>> 32 無符號右移32位,高32位變成低32位,再與原有的id進行異或運算,再強轉int取低32位

 

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;
    }

 

1.31是一個不大不小的奇素數,不至於乘以其他數時溢出,或太小以至於Hash表太小,分散不開

2.31會被JVM優化,31*i=(i<<5)-i;

String重寫hashCode算法的說明—— https://cloud.tencent.com/developer/article/1113699

 

4.Java 克隆方法——原型設計模式,深克隆和淺克隆的區別

淺克隆是引用的克隆,對象引用指向同一個對象

深克隆是克隆創建對象,對象地址不同

實現深度克隆的方式,實現Cloneable接口,重寫clone()方法

 

new創建對象時,首先查看new操作符後面的類型,知道了對象類型,才知道分配多大的內存空間。分配內存之後,再調用構造器函數,填充對象的個域,然後將他的引用(地址)發佈到外部,通過引用操作對象

clone方法跟new方法相似

 

5.wait()方法,每個對象都有monitor(即鎖)

如果調用對象wait()方法,當前線程必須擁有對象的monitor(即鎖),調用wait()必須在同步代碼塊中或同步方法裏面(synchorinized),否則會拋出java.lang.IllegalMonitorStateException異常

調用wait()方法時,相當於交出當前對象的monitor來釋放鎖,讓線程處於等待狀態,通過對象的notify()和notifyAll()方法來實現線程同步喚醒。這一點也是跟Thread.sleep()方法的區別,sleep()不釋放鎖

 

6. finalize() 方法

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章