1. 程式人生 > >結合原始碼分析==與equals與hashCode

結合原始碼分析==與equals與hashCode

.equals()與==

equals是所有類都具有的方法,注意基本八種資料型別是不具備equals方法的,只有他們對應的包裝類才具備。

//Character    
    public boolean equals(Object obj) {
        if (obj instanceof Character) {
            return value == ((Character)obj).charValue();
        }
        return false;
    }
//Byte
    public boolean equals(Object obj) {
        if (obj instanceof Byte) {
            return value == ((Byte)obj).byteValue();
        }
        return false;
    }
//Short
    public boolean equals(Object obj) {
        if (obj instanceof Short) {
            return value == ((Short)obj).shortValue();
        }
        return false;
    }
//Integer
    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }
//Long
    public boolean equals(Object obj) {
        if (obj instanceof Long) {
            return value == ((Long)obj).longValue();
        }
        return false;
    }
//Float
    public boolean equals(Object obj) {
        return (obj instanceof Float)
               && (floatToIntBits(((Float)obj).value) == floatToIntBits(value));
    }
//Double
    public boolean equals(Object obj) {
        return (obj instanceof Double)
               && (doubleToLongBits(((Double)obj).value) ==
                      doubleToLongBits(value));
    }
//Boolean
    public boolean equals(Object obj) {
        if (obj instanceof Boolean) {
            return value == ((Boolean)obj).booleanValue();
        }
        return false;
    }

可以看到基本上都是先判斷被equals的物件是不是同一個型別,如果不是則直接返回false。

如果是同一個型別則直接進行類似於.value()的方法,獲取這個value。進一步檢視原始碼可以發現最後這個方法的返回值都是基本資料型別。

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()方法,那他的底層實現是什麼樣:

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

我們可以看到無論如何包裝類也好,String也好,還是任何沒有重寫.equals的類也好,都進行了==的比較,如果兩個物件==那麼久說明為true,如果不等則返回false。那麼關於==的問題呢?什麼情況下==等於true呢?

下面先寫幾行程式碼,猜一猜最後的結果。

int 型別:

		Integer a1 = new Integer(1111);
		Integer c1 = new Integer(1111);
		System.out.println(c1==a1);
		System.out.println(c1.equals(a1));
	
		Integer a2 = new Integer(22);
		Integer c2 = new Integer(22);
		System.out.println(c2==a2);
		System.out.println(c2.equals(a2));
		
		int a3 = 3333;
		Integer c3 = new Integer(3333);
		System.out.println(c3==a3);
		System.out.println(c3.equals(a3));
//		System.out.println(a3.equals(c3));
		
		int a4 = 4444;
		int c4 = 4444;
		System.out.println(c4==a4);
//		System.out.println(c4.equals(a4));

下面大家思考一下結果是什麼:

false
true
false
true
true
true
true

至於Integer和int比較為什麼為True,請了解一下自動拆箱。

String 型別:

		String a1 = "1111";
		String c1 = "1111";
		System.out.println(c1==a1);
		
		String a2 = new String("2222");
		String c2 = new String("2222");
		System.out.println(c2==a2);
		
		String a3 = "3333";
		String c3 = new String("3333");
		System.out.println(c2==a2);

答案:

true
false
false

通過上述的分析可以得出如下結論:

1、基本資料型別不存在.equals方法

2、基本資料型別的==比較的是數值是否相等。

3、基本資料型別包裝類的==比較的是物件是否是相同的,也就是地址。new出來的東西就是不同的。

4、基本資料型別包裝類的.equals()方法比較的是值。

5、String型別的.equals()方法首先會比較是不是相同的物件,其次如果不是相同的物件會比較物件中的每一個字元是不是一樣的

6、String型別和其他Object型別的== 都是比較物件的地址,也就是是否是同一個物件。

7、如果沒有重寫equals方法 那麼預設物件相同equals為true

hashCode與==

下面我們看看hashCode方法與==方法的差異

		System.out.println("==================");
		Integer a1 = new Integer(1111);
		Integer c1 = new Integer(1111);
		System.out.println(c1==a1);
		System.out.println(a1.hashCode());
		System.out.println(c1.hashCode());
		System.out.println("==================");
		Integer a2 = new Integer(22);
		Integer c2 = new Integer(22);
		System.out.println(c2==a2);
		System.out.println(a2.hashCode());
		System.out.println(c2.hashCode());
		System.out.println("==================");
		int a3 = 3333;
		Integer c3 = new Integer(3333);
		System.out.println(c3==a3);
		System.out.println(c3.hashCode());
//		System.out.println(a3.hashCode());
		System.out.println("==================");
		Byte a4 = new Byte((byte) 1);
		Byte c4 = new Byte((byte) 1);
		System.out.println(c4==a4);
		System.out.println(a4.hashCode());
		System.out.println(c4.hashCode());
		System.out.println("==================");
		Long a5 = new Long(1);
		Long c5 = new Long(1);
		System.out.println(c5==a5);
		System.out.println(a5.hashCode());
		System.out.println(c5.hashCode());
		System.out.println("==================");
		String a6 = new String("123");
		String c6 = new String("123");
		System.out.println(c6==a6);
		System.out.println(a6.hashCode());
		System.out.println(c6.hashCode());
		System.out.println("==================");
		JDKProxyForUser jpu1 = new JDKProxyForUser();
		JDKProxyForUser jpu2 = new JDKProxyForUser();
		System.out.println(jpu1==jpu2);
		System.out.println(jpu1.hashCode());
		System.out.println(jpu2.hashCode());
==================
false
1111
1111
==================
false
22
22
==================
true
3333
==================
false
1
1
==================
false
1
1
==================
false
48690
48690
==================
false
1252169911
2101973421

下面我們檢視Byte型別的HashCode原始碼(其餘基本型別包裝類基本如此)

    /**
     * Returns a hash code for this {@code Byte}; equal to the result
     * of invoking {@code intValue()}.
     *
     * @return a hash code value for this {@code Byte}
     */
    @Override
    public int hashCode() {
        return Byte.hashCode(value);
    }

    /**
     * Returns a hash code for a {@code byte} value; compatible with
     * {@code Byte.hashCode()}.
     *
     * @param value the value to hash
     * @return a hash code value for a {@code byte} value.
     * @since 1.8
     */
    public static int hashCode(byte value) {
        return (int)value;
    }

下面我們再檢視其他型別hashCode原始碼

/**
     * Returns a hash code value for the object. This method is
     * supported for the benefit of hash tables such as those provided by
     * {@link java.util.HashMap}.
     * <p>
     * The general contract of {@code hashCode} is:
     * <ul>
     * <li>Whenever it is invoked on the same object more than once during
     *     an execution of a Java application, the {@code hashCode} method
     *     must consistently return the same integer, provided no information
     *     used in {@code equals} comparisons on the object is modified.
     *     This integer need not remain consistent from one execution of an
     *     application to another execution of the same application.
     * <li>If two objects are equal according to the {@code equals(Object)}
     *     method, then calling the {@code hashCode} method on each of
     *     the two objects must produce the same integer result.
     * <li>It is <em>not</em> required that if two objects are unequal
     *     according to the {@link java.lang.Object#equals(java.lang.Object)}
     *     method, then calling the {@code hashCode} method on each of the
     *     two objects must produce distinct integer results.  However, the
     *     programmer should be aware that producing distinct integer results
     *     for unequal objects may improve the performance of hash tables.
     * </ul>
     * <p>
     * As much as is reasonably practical, the hashCode method defined by
     * class {@code Object} does return distinct integers for distinct
     * objects. (This is typically implemented by converting the internal
     * address of the object into an integer, but this implementation
     * technique is not required by the
     * Java&trade; programming language.)
     *
     * @return  a hash code value for this object.
     * @see     java.lang.Object#equals(java.lang.Object)
     * @see     java.lang.System#identityHashCode
     */
    public native int hashCode();

可以得出結論:

1、基本資料型別沒有hashCode()方法。

2、基本資料型別的包裝類的hashCode為包裝類的基本型別的值。

3、hashCode相同並不代表==等於true,也就是並不是同一個物件。

4、hashCode不同則肯定不是同一個物件。

5、兩個物件equals則hashCode一定相同。