Java中的==与equal详细解析


Java中的八大基本数据类型:byte、short、int、long、float、double、boolean、char。

String类型、还有Integer、Long等包装类型,都属于引用数据类型,也就是一个个对象。

==

1.基本类型比较时,==比较的是值。

int a = 127;
int b = 127;
System.out.println(a==b);//true

2.引用类型比较时,==比较的是对象的引用。

Integer等包装数据类型为例:

Integer i1 = new Integer(127);
Integer i2 = new Integer(127);
System.out.println(i1==i2);//false

String类型为例:

String s1 = new String("suvue");
String s2 = new String("suvue");
System.out.println(s1==s2);//false

普通对象为例:

@Data
class Suvue{
    private String name;

    public Suvue(String name) {
        this.name = name;
    }
}
public class Balabala {
    public static void main(String[] args){
        Suvue suvue1 = new Suvue("这是我的名字");
        Suvue suvue2 = new Suvue("这是我的名字");
        System.out.println(suvue1==suvue2);//false
    }
}

3.Integer等包装数据类型中缓存池的作用。

先来看下面代码中的一个现象吧。

Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1==i2);//true
Integer i3 = -128;
Integer i4 = -128;
System.out.println(i3==i4);//true

看了代码很不解,包装类型用==比较,竟然返回的true!

这是因为在Integer、Long等包装类中,有一个可变大小的缓存池,默认的范围都是 -128~127。

来看下这个缓存池的源码吧!(篇幅有限只截取重要部分)

private static class IntegerCache {
        static final int low = -128;
        static final int high;
    	//我们说的缓存池就是下面这个东西
        static final Integer cache[];

        static {
            // 池子的上限我们可以进行配置
            int h = 127;
            //...获取自定义上限值的代码(此处省略)
            
            // 上限值不能小于127
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

​ 创建一个缓存池很简单吧,底层其实就是一个int类型的数组而已,只不过可以自定义数组内元素值的上限嘛。

​ 我们先来分析一下,像Integer i1 = 127;这样的代码,i1为Integer类型,127为int类型,Integer与int又没有继承关系,一般情况下,这样的代码编译时会报错的!但是由于Java中的自动装箱机制,Java会自动将int类型转换为Integer类型,即:Integer i1 = Integer.valueOf(127);

那么我们来看下,调用Integer.valueOf()时,Integer的缓存池是怎么使用的吧!

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

​ 解释下这段源码吧,当int类型的数值在缓存池的范围内(默认为-128~127)时,从缓存池中;不在这个范围内的话,就new一个对象返回。

所以我们测试代码中的数据127和-128都在缓存池内,这里以127为例,两次都取到数据都是缓存池中的127,所以比较的结果时true。

上文我们提到了自定义常量池的上限值,具体的做法请参照笔者的这篇博文 https://blog.csdn.net/weixin_45612794/article/details/100770028 这里就不多叙述了。

4.String数据类型中字符串常量池的作用。

先来看下这段测试代码吧!

String s1 = "suvue";
String s2 = "suvue";
System.out.println(s1==s2); //true
String s3 = "中国";
String s4 = "中国";
System.out.println(s3==s4); //true

上面代码为true的原因,比如

第一次执行String s1 = "suvue";这段代码时,会去JVM的字符串常量池中查找,发现之前没有“suvue”这个字符串,那么会在字符串常量池中申请一块空间,新建一个"suvue"字符串并返回它在字符串常量池中的引用给s1。

当第二次执行String s2 = "suvue";会去JVM的字符串常量池中查找,此时发现已经有了“suvue”这个字符串,那么直接返回它在字符串常量池中的引用给s2。

“==”比较对象时,比较的是否是同一对象的引用。此时发现s1和s2是同一个引用,那么打印的结果自然是true了。

2.equals()

2.1.普通对象

先看个测试代码吧

Balabala o1 = new Balabala();
Balabala o2 = new Balabala();
System.out.println(o1.equals(o2));//false 

Java中所有的对象,都隐式的集成了Object类,所以一般情况下调用的都是Object的equals方法,我们看下它的代码实现吧!

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

我们看到,它的默认实现,其实调用的是==。那么就不难理解为啥是false了。

2.1 Integer等包装类型对象

Integer i1 = new Integer(128);
Integer i2 = new Integer(128);
System.out.println(i1.equals(i2));//true

结果为true的原因,是因为Integer类重写了Object的equals方法,相当于比较的是两个Integer对象的int值。

来看下equals方法的源码实现吧!

public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}

代码很简单,我就不多解释了哈。

2.3 String对象

老规矩,先来看测试代码。

String s1=new String("suvue");
String s2=new String("suvue");
System.out.println(s1.equals(s2));//true

为true的原因也很简单,同样是String类重写的equals方法。看下重写过后的equals方法吧!

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

​ 上述代码大致意思,就是去遍历计较两个String对象的char数组,从头到尾都一直的话,就返回true了。

3.小结

1.当使用==时,如果比较的是八大基本类型的值,直接看值是否相等;如果有任一方有new关键字存在(比较的是对象),结果肯定是false了;如果是包装类型的话,首先要判断是否在缓存池中;如果是String类型的,因为有字符串常量池的存在,只要字面值一样,结果就是true。

2.当使用equals时,除了包装类型和String类之外,其他比较的都是对象的内存地址。

笔者可能总结的不太好,所以还是要多多理解与实战!

发布了46 篇原创文章 · 获赞 13 · 访问量 3030

猜你喜欢

转载自blog.csdn.net/weixin_45612794/article/details/104008837