Java中从源码看==和equals()以及compareTo()和compareToIgnore()的原理和区别

技术有限,才疏学浅,如有表述不正确或有不足,欢迎吐槽、指导和交流。
————————————————————————————————————
Java中 == 和 equals()的使用非常频繁, 以及String类的compareTo()和compareToIgnoreCase()的使用也很多,这里根据源代码分析一下各自的原理和区别。

1、== 运算符

== 是一个比较运算符。可用于基本数据类型或引用数据类型。
基本数据类型直接用值比较是否相同;
举个栗子:

	int a = 5;
	int b = 5;
	System.out.print(a == b);//结果输出true

引用数据类型,比较引用的内存地址值,引用的内存地址相同返回true,不同返回false。
例子1:

	User a = new User("zhangsan");   //new一个对象,声明变量名a保存该对象的内存地址
	User b = a;   //声明另一个变量名b,将a保存的内存地址赋值给b
	System.out.print(a == b);  //二者保存的内存地址相同,都指向同一个对象,输出true

例子2:

	User a = new User("zhangsan");//new一个对象,声明变量名a保存该对象的内存地址
	User b = new User("zhangsan");//再new一个对象,声明变量名b保存该对象的内存地址
	System.out.print(a == b);//二者指向的对象名字都叫"zhangsan",但内存地址不同,输出false

不过对于String类型,情况有点特殊:
例1:

	String a = new String("5");
	String b = a;
	System.out.print(a == b);//输出true

例2:

	String a = new String("5");
	String b = new String("5");
	System.out.print(a == b);//输出false

例3:

	String a = "5";
	String b = "5";
	System.out.print(a == b);//输出true

例1,例2还好理解,例3和例2代码看起来没啥区别,结果却完全不同。
这是因为:例2的声明方式

是在堆中创建了两个String类型的对象,a,b保存的是指向不同对象的内存地址

而例3的声明方式

"5"实际上是保存在字符串常量池(StringConstantPool)中,每次声明都是先去常量池中看有没有这个常量,无则创建并返回引用地址,有则直接返回引用地址。a,b此时保存的都是指向"5"这个常量的地址

2,equals()方法

equals()是顶级根类Object中的方法

可见equals()仅仅用于引用数据类型的比较,默认的equals()方法源代码:

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

直接调用 == 运算符,比较两者的内存地址。

而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;//String的本质是char数组,value就是这个数组
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {//比较两者的每一个char元素
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

String类型的equals()比较步骤:

1,先比较两者内存地址,即默认equals()的比较(比较内存地址)
2,内存地址不同的时候,判断是否String类型对象作为比较依据(比较是否String对象)
3,以上1 false、2 true的情况下,比较两者长度是否相同(比较长度)
4,3 true的情况下,比较两者的本质——char数组相同索引下的各个元素是否完全相同(比较元素组成)

3、compareTo()方法

compareTo()是String类的比较方法,返回的不再是boolean值,而是int值。
源代码如下:

public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

compareTo()的比较步骤:

1, 以长度最小的对象为基准,比较两者索引相同的每一个char元素,有不同,返回两个不同元素的ASCII编码(貌似仅限英文,其他文字是Unicode编码)之差。
例如"a".compareTo(“A”), 就是a的元素编码 - A的元素编码,返回值是32,反过来返回值是 -32.
2,如果可比较的元素编码完全相同,则比较两者长度,返回长度差。
例如"string".compareTo(“stringanother”),就是6 - 13,返回 -7;
“string”.compareTo(“string”),就是6 - 6,返回0

4、compareToIgnoreCase()

字面意思就是忽略(ignore)大小写(case)的比较(compare),不过实现方法不是简单的重写compareTo(),源代码如下:

public int compareToIgnoreCase(String str) {
        return CASE_INSENSITIVE_ORDER.compare(this, str);
    }

这里是调用了CASE_INSENSITIVE_ORDER常量的compare方法,
看下CASE_INSENSITIVE_ORDER对应的源代码:

public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                         = new CaseInsensitiveComparator();
    private static class CaseInsensitiveComparator
            implements Comparator<String>, java.io.Serializable {
        // use serialVersionUID from JDK 1.2.2 for interoperability
        private static final long serialVersionUID = 8575799808933029326L;

        public int compare(String s1, String s2) {
            int n1 = s1.length();
            int n2 = s2.length();
            int min = Math.min(n1, n2);
            for (int i = 0; i < min; i++) {
                char c1 = s1.charAt(i);
                char c2 = s2.charAt(i);
                if (c1 != c2) {
                    c1 = Character.toUpperCase(c1);
                    c2 = Character.toUpperCase(c2);
                    if (c1 != c2) {
                        c1 = Character.toLowerCase(c1);
                        c2 = Character.toLowerCase(c2);
                        if (c1 != c2) {
                            // No overflow because of numeric promotion
                            return c1 - c2;
                        }
                    }
                }
            }
            return n1 - n2;
        }

原来这是String的内部私有静态类CaseInsensitiveComparator(大小写不敏感比较器)的常量对象,对应的方法是重写的Comparator(比较器)的compare()方法。
和compareTo的比较步骤很相似:

1,以长度最小的对象为基准,比较两者索引相同的每一个char元素,如果编码不同,转化为大写继续比较,如果还是不同转化为小写再次比较,如果还是不同,返回转化为小写后的编码差值。
2,如果可比较的元素原始/大写化后/小写化后的编码完全相同,则比较两者长度,返回长度差。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值