关于数据equals和== 的区别:
本质区别:equals 比较的是值的hashcode;
而 == 比较的值的内存地址是否一样。
以下以String 为例:
根据String 源码中方法intern()返回值为String;英文释义:拘留,软禁。
顾名思义:从软禁区域获取一个String 并返回。软禁区域则为 常量池。
非new的情况:
String a = “abc”;
String b = “abc”;
a == b ;//结果:true
释义:a 对象形成的时候,会在常量池中找有没有“abc”的字符串;如果没有,形成一个“abc”字符串在常量池。并在栈中将句柄(引用)指向常量池。b同理,则指向的为同一个,abc的地址则为同一个地址。所以为true。
new的情况:
String a = new String(“abc”);
String b = new String(“abc”);
a == b ;//结果: false
释义: a对象形成的时候,会先去常量池中找有没有“abc”的字符串,若没有,则在常量池中创建一个abc的对象,并拷贝一份,放在堆中。将栈中句柄a指向堆中地址(假设地址别名为:上海)。b则同a一样操作,只不过,a形成的时候已经在常量池中产生了“abc”,b则直接拷贝一份,放在堆中,并将栈中句柄b指向堆中地址(假设地址别名为:北京)则北京和上海地址不一致。(个人见解缘由:每次去常量池中的判断,为了提高性能,提高效率,节约开销。)
总结:非new的情况下,会指向常量池中,new的情况下会指向堆中。
进阶一步:
String a = “kfc”;//常量池中地址假设:南京
String b = “mds”;//常量池中地址假设:苏州
String c = a+b;//c的地址为堆中地址假设:江苏
前方高能:c = new StringBuilder().append(a).append(b).toString();
注意:StringBuilder类中的toString()源码返回值为:new String(xxx);c在运行时实际上形成的是一个新的字符串新的地址。
c == (a+b);//显然为false;
String d = "nbacba";//假设常量池中地址为:无锡
String e = "nba"+"cba";//e的字面还是nbacba;显然地址为无锡。
d == e;//结果true;
再进一步:
public Test{
public static final a = “kfc”;
public static final b = “mds”;
String c = a+b;//注意:a,b在编译阶段已经形成了常量;所以c = “kfc”+”mds”;//同样为常量池中的地址,假设为:上海
String d = “kfc”+”mds”; //常量池的地址同样为上海。
c == d ;//结果:true
}
接下来开始解析String 源码方法intern:
String a = new String(“abc”);//地址为堆中(假设地址别名:上海),常量池中“abc”地址假设为深圳。
String b = a.intern();//根据文章开头所示:b 则指向的是深圳。
String c = “abc”;//c 是从常量池中直接获取,则指向深圳。
a == b ;//结果false
b == c;//结果true
所有数据类型总结:
1.基本数据类型 byte short int long char float double boolean;
== 比较的是 值是否相等。
注意:没有实现常量池的Float和Double。
如栗子:
Double a = 1.0;
Double b = 1.0;
a == b; //false
2.引用数据类型:自定义的对象,数组等等。
一般情况下,equals和==是一样的都是比较的两者的地址值是不是一样。
但是有特殊的情况:我们都知道我们使用的类都是继承自Object基类,
Object中equals方法中是使用==来实现的,即比较的是两者的地址值。
比如Date、String、Integer等类都是重写了equals都是重写了,比较的是值是否相等。
关于未重写的equals比较都均为hashCode值。