基于基本类型对“==”和“equals()”的探究

首先声明所有的探究都是基于jdk1.8.0_144版本上进行的。

开始之前我们先来看一段代码:

查看代码


        int x = 0;
        double y = 0.0;
        System.out.println(x == y);//true
        System.out.println(Integer.hashCode(x));//0
        System.out.println(Double.hashCode(y));//0
        System.out.println(Objects.equals(x, y));//false

这里我们声明了两个不同类型的变量,并且给他们赋了不同的值,可以用“==”进行判断是发现返回的值是true,这个返回结果并不是我们所期待的,调用equals()方法返回的结果才是我们想看到的。同时,我们也看到了两个变量他们的哈希码值是一样的,这又是为什么呢?

首先我们要知道java语言中是如何来给变量进行赋值的。

        Double m = Double.valueOf(9.9);//包箱
        double n = m.doubleValue();//拆箱
        Integer x = Integer.valueOf(6);//包箱
        int y = x.intValue();//拆箱

在Java中变量的赋值并不是我们所看到的那样单纯的将值赋给变量。每个基本数据类型Java中都会有一个对应的包装类,每个类中调用.valueOf()就是对值进行自动包箱,调用.基本类型名Value()自动拆箱。下面我们来看一个例子:

查看代码


        System.out.println("==========Integer==========");
        Integer a = new Integer(99);
        Integer b= new Integer(99);
        System.out.println(a == b);//false
        System.out.println(b.equals(a));//true
        Integer c = Integer.valueOf(99);
        Integer d = Integer.valueOf(99);
        System.out.println(c == d);//true
        System.out.println(c.equals(d));//true
        int e = c.intValue();
        System.out.println(Integer.hashCode(e));//99
        int f = d.intValue();
        System.out.println(Integer.hashCode(f));//99
        System.out.println(e == f);//true
        System.out.println(Objects.equals(e,f));//true

这里我们先new了两个Integer类。此时堆中会有两个new的Integer类,用“==”进行判断返回值是false,由此我们可以看到“==”是比较两个对象的内存地址是否相同的。后面我们对数据进行Integer类型的包箱,此时用“==”进行判断返回值是true。好,我们来看一下valueOf()方法:

    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

这时候我们发现valueOf()方法中有一个IntegerCache的类:

查看代码


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

        private IntegerCache() {}
    }
    /**
     * Cache to support the object identity semantics of autoboxing for values between
     * -128 and 127 (inclusive) as required by JLS.
     *
     * The cache is initialized on first usage.  The size of the cache
     * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
     * During VM initialization, java.lang.Integer.IntegerCache.high property
     * may be set and saved in the private system properties in the
     * sun.misc.VM class.
     */

通过注解可以知道这个缓存池是存在一个范围的下限是-128,上限是127(包含127)。缓存在第一次使用是会被初始化,它的大小可能由AutoBoxCacheMax=<size>这个选项控制。此时,变量c,d都是存放缓存中99所在的内存地址,因此"=="判断返回的是true。

接下来我们来看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;
    }

equals()比的是两个对象的值,所以即使不是同一个对象,他们的值是相同的那么返回的值也是true。

ok,我们Integer类讲完了那我们来看看Doule类看看会有什么不一样呢?我先看一段代码:

查看代码


        System.out.println("==========Double==========");
        Double j = new Double(123.0);
        Double k = new Double(123.0);
        System.out.println(j == k);//false
        System.out.println(j.equals(k));//true
        Double m = Double.valueOf(123);
        Double n = Double.valueOf(123);
        System.out.println(m == n);//false
        System.out.println(m.equals(n));//true
        System.out.println("------------------");
        double x = m.doubleValue();
        System.out.println(Double.hashCode(x));//1079951360
        double y = n.doubleValue();
        System.out.println(Double.hashCode(y));//1079951360
        System.out.println("-------------------");
        System.out.println(Objects.equals(x, y));//true
        System.out.println(x == y);//true

如果按照前面Integer类的情况,我们调用完valueOf()方法后应该会初始化一个缓存区,我们会从缓存区中得到我们想到的数据,将数据在缓存区中的内存地址赋值给变量。可是实际上并不是这样的。

    public static Double valueOf(double d) {
        return new Double(d);
    }
    public Double(double value) {
        this.value = value;
    }
    private final double value;
    public double doubleValue() {
        return value;
    }

它会new一个新的Double类将数据进行包箱,所以“m==n”返回值是false,它没有我们上面所讲的缓存区这一个说法。上面我们讲了equals()是对于对象值的比较因此返回的是true;由于doubleValue()是直接返回Double类包箱的值,返回出x,y的hashCode()值发现他们的哈希码值是相同的即他们是同一个对象。所以“x==y”返回值也为true。

posted on 2022-03-23 18:00  vernier_caliper  阅读(33)  评论(0)    收藏  举报