Java中equals()方法分析
绝对是一道笔试题引发的‘血案’,前两天参见某公司的面试题,其中考到了关于Java中equals()方法的一道题。话不多说,先看一下这个题:
Integer i=100,j=100,s=128,k=128; System.out.print(i==j); System.out.print(i.equals(j)); System.out.print(s==k); System.out.print(s.equals(k));
结果为:true true false true
原因:JVM使用缓存池来管理整型,并且范围在-128到127如果int直接超过这个返回,那么Integer会调用构造器创建一个新的Integer对象,例如题目中
k=128s=128
其实质是相当于
Integer s=new Integer(128);
Integer K=new Integer(128);
上面题目代码可等价转换如下代码:
Integer i=new Integer(100); Integer j=i; Integer s=new Integer(128); Integer K=new Integer(128); System.out.print(i==j); System.out.print(i.equals(j)); System.out.print(s==k); System.out.print(s.equals(k));
在java中引用类型,比较方式有两种equals()和==
equals()和==比较变量类型区别:
使用==比较的变量有两种类型:
1、比较变量均为基本数值类型,则只要两个变量的值相等,就返回true;
2、比较变量为引用类型变量,只有它们指向同一个对象时,才返回true;
PS:==用于比较引用类型时必须一致或者为父子关系的对象。
使用equals()比较的变量为引用类型变量。
所有的类都继承与object类,我们先看以下object中equals()方法
public boolean equals(Object obj) { return (this == obj); }
可以了解到object中equals()方法是有==操作符来实现的。因此只要比较实例的类没有重写equals()方法,那么equals()方法与==比较的结果是一致的。都表示内存中存放地址的比较。
根据equals()方法是否被重写,将所有的引用类型分为:重写型(equals()方法被重写)、继承性
一、继承性(equals()方法没有被重写)
对于equals()方法没有被重写的引用类型,只要是被同一个new创建的实例,起比较的结果都为true,否则为false
此时== 与equals()等价
例如:
A a=new A(); A b=new A(); A c=a; System.out.println(a.equals(b)); System.out.println(a==b); System.out.println(a.equals(c)); System.out.println(a==c);
结果:false false true true
这表明new表示在JVM堆中创建一个新的空间来存放实例。所以a和b变量指向不同的内存空间。a和c指向同一空间。
一、重写型(equals()方法被重写)
这里介绍几个JDK中已经对equals()方法重写的类。
1、String
下来看一下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; }
源码分析:
if (this == anObject) :当两个String类型实例指向同一内存空间,答案是肯定的true
if 当两个实例并不指向同一内存空间时,分析源码可以知道,当这两个实例的字符串内容相同时,仍然返回true。
总结:String 的equals()方法比较的实质是两个字符串内容是否相等,与内存地址无关
String通过==比较的是内存地址(==比较内存地址是不会变的)
例如:
String a="one"; String b="one"; String c=new String("one"); System.out.print(a.equals(b)); System.out.print(a.equals(c)); System.out.println(a==b); System.out.println(a==c);
于此类似的还有Integer、Date,它们都对equals()方法重写,比较的是指都是实例的内容而不是内存地址。
这里String的直接赋值也是JVM缓存池的作用在里面。因此a,b的内存地址一致。
回归到题目中,Integer的equals()也是比较的内容,因此只要内容值相等,equals()方法就返回true.
System.out.print(s.equals(k));
System.out.print(i.equals(j));
返回true;
按照道理将System.out.print(s==k);应该与System.out.print(i==j);一样都应该返回true.但是没有因为这里有点特殊,牵扯到了Java中常量池的内容。这里简要说一下,int常量池中初始化-128~127的范围,所以Integer i 当i的值在范围之内,取数值,而当i超出范围时,需new 一个新的实例,地址将发生变化。
因此System.out.print(s==k); 输出值为false