淘先锋技术网

首页 1 2 3 4 5 6 7

==和equals的区别
之前做密码校验的时候,遇到了这个问题,当时因为不清楚两者区别,导致了一次bug,现在打算好好分析一下
举个例子

int i=1;
String s="123";
String s2="123";
String s3=new String("123");
boolean res=i==1;//true
boolean res2=s=="123";//true
boolean res3=s==s2;//true
boolean res4=s==s3;//false

一开始我也很懵逼,什么东西这是???
首先来说说==,这是一个运算符用来比较两个变量是否相等.这里说的是变量哦,不是对象,就是JAVA中的8大基本类型(4+2+1+1)byte short int long+float double+char+boolean.
那么java是和我们一样比较数值来判断两个变量是否相等的吗?当然不是了,如果是的话为什么不用两个变量相减是否为0判断呢.

实际java是通过比较两个基本类型变量的内存地址是否相等,这些基本类型会变成包装类被存在jvm里的常量池里,所以我们生成的变量只是一个引用指向这些基本类型包装类,自然我们的内存地址相等。

接下来是String,为什么用new和不用new结果不一样呢,

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

通过源码我们发现String是final就是不可修改的.在java编译的时候会把“123”存入class文件常量池,源码里String是char[],char是基本类型外加String是不可修改我们是不是也可以把其当做一种复合基础类型,所以会被放在常量池内。那么同理s和s2都是指向相同地址的两个不同引用,所以==结果是true

接下就是new String(),生成了一个新的String对象

/**
 * Initializes a newly created {@code String} object so that it represents
 * the same sequence of characters as the argument; in other words, the
 * newly created string is a copy of the argument string. Unless an
 * explicit copy of {@code original} is needed, use of this constructor is
 * unnecessary since Strings are immutable.
 *
 * @param  original
 *         A {@code String}
 */
public String(String original) {
    this.value = original.value;
    this.hash = original.hash;
}

/**
 * Allocates a new {@code String} so that it represents the sequence of
 * characters currently contained in the character array argument. The
 * contents of the character array are copied; subsequent modification of
 * the character array does not affect the newly created string.
 *
 * @param  value
 *         The initial value of the string
 */
public String(char value[]) {
    this.value = Arrays.copyOf(value, value.length);
}

通过源码我们发现如果传入的是String会拷贝其hash,变成传入String的一个副本.但是传入的是char[]只会对value进行拷贝不会对hash进行拷贝所以res4结果为false.
String继承自Object,所以其归根结底还是一个对象,使用=“123”就是做了一个引用,使用new才真正新建了一个对象.

理解了这一点,所以String的比较应该用object类必备的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;
}

一上来先比较一内存地址,如果内存地址一样那就返回相等不用比了,说明两者都是指向同一个
发现内存地址不一样那么就要先判断是不是String对象,是String对象这里因为传入是Object所以这里做了类型转换,然后就是对两者char[]进行遍历对比了,如果相同就返回true.

***结论:==针对内存地址进行比较,适用于常量比较
equals():更注重于内容相等,而非内存地址相等,适用于对象比较
打个比方
equals就像 我喜欢吃豆沙馅的面包,那么对我来说只要面包的内容是豆沙馅不管在哪里买的对我来说都是一样好吃

==就像 我喜欢家边上的那家面馆的牛肉面,全世界有且只有这一家唯一的,我可以叫外卖或者到店里吃,最后都是指向这一家店,都是一样好吃***