天天看點

Java判等問題:細節決定成敗Java判等問題:細節決定成敗

Java判等問題:細節決定成敗

Java判等問題:細節決定成敗Java判等問題:細節決定成敗

判等問題,在我們代碼中就是一句話的事情,但是這一行代碼如果處理不好,不僅會出現緻命的bug,下面我們就以Java中 equals、compareTo 和 Java 的數值緩存、字元串駐留等問題展開讨論

1. 注意 equals 和 == 的差別

在業務代碼中,我們通常使用 equals 或 == 進行判等操作。equals是方法而 ==是操作符

: 1.對基本類型,比如 int 、long、進行判斷,隻能使用 == ,比較對是直接值,因為基本類型對值就是其數值

: 2.對引用類型,比如Integer 、Long 和 String 進行判等,需要使用 equals 進行内容判等。因為引用類型,需要使用equals進行内容判等。因為飲用類型等直接值是指針,使用 == 的話,比較的是指針,也就是兩個對象在記憶體中的位址,即比較他們是不是同一個對象,而不是比較對象内容

結論:
  • 比較值的内容,除了基本類型隻能使用 ==外,其他類型都需要使用 equals。
案例:
public static void main(String[] args) throws Exception {
        Integer a = 127;
        Integer b = 127;
        System.out.println(" a == b " +(a == b));

        Integer c = 128;
        Integer d = 128;
        System.out.println(" c == d " + (c == d));

        Integer g = new Integer(127);
        Integer h = new Integer(127);
        System.out.println(" g == h " + (g == h));

        Integer i = 128;
        int j = 128;
        System.out.println(" i == j " + (i == j));
    }           

結果 :

a == b true
 c == d false
 g == h false
 i == j true           
  • 在 a == b 中,編譯器會把 a = 127 轉換為 Integer.valueOf(127),源碼可以發現,這個轉換是内部其實做了緩存,使得兩個 Integer 指向同一個對象 是以傳回true
public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }           
  • 在 c == d 中使用128 傳回false ,Integer 當不符合-128 127值範圍時候。記住用的:new,開辟新的記憶體空間,不屬于IntergerCache管理區
private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

           
  • 在g == h案例中,New 出來的 Integer 始終是不走緩存的新對象。比較兩個新對象,

    或者比較一個新對象和一個來自緩存的對象,結果肯定不是相同的對象,是以傳回 false。

2. equals 沒有這麼簡單

如果看過 Object 類源碼,你可能就知道,equals 的實作其實是比較對象引用:

public boolean equals(Object obj) {
        return (this == obj);
    }           
重點(注意點):
  • 不重寫equals方法與“ == ”一樣,用于比較對象的引用是否相等。

之是以 Integer 或 String 能通過 equals 實作内容判等,是因為它們都重寫了這個方法。

String 的 equals 的實作:

/**
     * Compares this string to the specified object.  The result is {@code
     * true} if and only if the argument is not {@code null} and is a {@code
     * String} object that represents the same sequence of characters as this
     * object.
     *
     * @param  anObject
     *         The object to compare this {@code String} against
     *
     * @return  {@code true} if the given object represents a {@code String}
     *          equivalent to this string, {@code false} otherwise
     *
     * @see  #compareTo(String)
     * @see  #equalsIgnoreCase(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;
    }           

Integer.equals.()

/**
     * Compares this object to the specified object.  The result is
     * {@code true} if and only if the argument is not
     * {@code null} and is an {@code Integer} object that
     * contains the same {@code int} value as this object.
     *
     * @param   obj   the object to compare with.
     * @return  {@code true} if the objects are the same;
     *          {@code false} otherwise.
     */
    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }           

個人部落格位址:

http://blog.yanxiaolong.cn/