java ==与equals的区别
首先上一段代码进行分析:
public class test20210122_001 {
public static void main(String[] args) {
int a1=1;
int a2=1;
Integer a3=1;
Integer a4=1;
Integer b1 =new Integer (1);
Integer b2 =new Integer (1);
String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");
String s4 = new String("hello");
System.out.println(a1 == a2); // true
System.out.println(a1 == a3); // true
System.out.println(a3 == a4); // true
System.out.println(a3 == b1); // false
System.out.println(a1 == b1); // true
System.out.println(a1 == b2); // true
System.out.println(b1 == b2); // false
System.out.println("-------------------------");
System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // false
System.out.println(s1 == s4); // false
System.out.println(s3 == s4); // false
}
}
public class test20210122_002 {
public static void main(String[] args) {
objPoolTest();
}
public static void objPoolTest() {
int i = 40;
int i0 = 40;
Integer i1 = 40;
Integer i2 = 40;
Integer i3 = 0;
Integer i4 = new Integer(40);
Integer i5 = new Integer(40);
Integer i6 = new Integer(0);
Double d1=1.0;
Double d2=1.0;
System.out.println("i==i0\t" + (i == i0)); //true
System.out.println("i==i1\t" + (i == i1)); //true
System.out.println("i==i2\t" + (i == i2)); //true
System.out.println("i==i4\t" + (i == i4)); //true
System.out.println("i==i5\t" + (i == i5)); //true
System.out.println("i1==i2\t" + (i1 == i2)); //true
System.out.println("i1==i4\t" + (i1 == i4)); //false
System.out.println("i1==i5\t" + (i1 == i5)); //false
System.out.println("i4==i5\t" + (i4 == i5)); //false
System.out.println("d1==d2\t" + (d1==d2)); //false
System.out.println("i1==i2+i3\t" + (i1 == i2 + i3)); //true
System.out.println("i4==i5+i6\t" + (i4 == i5 + i6)); //true
}
}
估计很多人已经感觉头晕了,下面我们来具体分析一下原因
在分析原因之前一定要先搞懂==与equals的区别:
==表示两者的内存地址是相同的,既然内存地址是相同的,那么肯定指的是同一个元素(数据/对象)
equals表示两者所指的元素相等,相等不一定就是同一个元素,比如说:我有一元硬币,你也有一元硬币,我的一元硬币和你的一元硬币是相等的,但不是同一个一元硬币!
注意:==为true的两个元素equals肯定为true,equals为true的两个元素==不一定为true
public class test20210122_003 {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
}
}
输出结果为:s1 == s2
分析:首先程序会在这个String缓冲池中寻找相同值的对象,当s1="hello"时发现池中没有"hello",于是就将s1先放到了池中,所以在s2被创建的时候,程序找到了具有相同值("hello")的 s1,于是将s2也指向了s1所引用的对象"hello"。
public class test20210122_003 {
public static void main(String[] args) {
String s1 = "hello";
String s2 = new String("hello");
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
if (s1.equals(s2))
System.out.println("s1 equals s2");
else
System.out.println("s1 not equals s2");
}
}
输出结果为:
s1 != s2
s1 equals s2
分析:首先程序会在这个String缓冲池中寻找相同值的对象,当s1="hello"时发现池中没有"hello",于是就将s1先放到了池中,但是在s2被创建的时候,程序不希望再在池里寻找旧的"hello",想在堆里面重新创建一个"hello"对象,
于是s1和s2的值虽然相同但是所指的对象却不是同一个,s1指的是池里面的"hello",s2指的是堆里面新创建的"hello"。
public class test20210122_003 {
public static void main(String[] args) {
String s1 = "hello";
String s2 = new String("hello");
s2 = s2.intern();
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
if (s1.equals(s2))
System.out.println("s1 equals s2");
else
System.out.println("s1 not equals s2");
}
}
输出结果为:
s1 == s2
s1 equals s2
intern() 作用:检查字符串池里是否存在"hello"这么一个字符串,如果存在,就返回池里的字符串;如果不存在,该方法会把"hello"添加到字符串池中,然后再返回它的引用。
也可以像下面这样操作:
String s1 = "hello";
String s2 = new String("hello").intern();
System.out.println("s1 == s2"); 输出:true
针对基本数据类型和封装类型的判断:
int(Integer),char(Character),double (Double), float(Float),long(Long),short(Short),byte(Byte),boolean(Boolean)
public static void main(String[] args) {
int i = 40;
int i0 = 40;
Integer i1 = 40;
Integer i2 = 40;
Integer i3 = 0;
Integer i4 = new Integer(40);
Integer i5 = new Integer(40);
Integer i6 = new Integer(0);
Double d1=1.0;
Double d2=1.0;
System.out.println(i == i0); //true i和i0均是普通类型(int)的变量,所以数据直接存储在栈中,而栈有一个很重要的特性:栈中的数据可以共享。当我们定义了int i = 40;,再定义int i0 = 40;这时候会自动检查栈中是否有40这个数据,如果有,i0会直接指向i的40,不会再添加一个新的40。
System.out.println(i == i1); //true 虽然返回值是true,但是暂时不知道为什么,有哪位大佬知道的可以留言!一般很少在不同数据类型之间作比较。
System.out.println(i == i2); //true
System.out.println(i == i4); //true
System.out.println(i == i5); //true
System.out.println(i1 == i2); //true i1和i2均是引用类型,在栈中存储指针,因为Integer是包装类。由于Integer包装类实现了常量池技术,因此i1、i2的40均是从常量池中获取的,均指向同一个地址,因此i1=12。
System.out.println(i1 == i4); //false 由于i4和i5要求重新创建对象,不再重常量池里面拿旧的了,所以i4和i5指的都是新的各自独一无二的对象地址
System.out.println(i1 == i5); //false
System.out.println(i4 == i5); //false
System.out.println(d1==d2); //false d1和d2均是引用类型,在栈中存储指针,因为Double是包装类。但Double包装类没有实现常量池技术,因此Doubled1=1.0;相当于Double d1=new Double(1.0);,是从堆new一个对象,d2同理。因此d1和d2存放的指针不同,指向的对象不同,所以不相等。
System.out.println(i1 == i2 + i3); //true 很明显这是一个加法运算,Java的数学运算都是在栈中进行的,Java会自动对i1、i2进行拆箱操作转化成整型,因此i1在数值上等于i2+i3。
System.out.println(i4 == i5 + i6); //true
}
重点注意:
除了double/Double类型,其他的基本类型和包装类均实现了常量池技术,
但是常量的范围是在-128,127之间的范围,如果超出了这个范围,就不能再从常量池中查找,只能在堆中创建新的了。
例如:Integer i1 = 400; Integer i2 = 400;,超过了127,无法从常量池获取常量,就要从堆中new新的Integer对象,这时i1和i2就不相等了。
==和equals一般是同类型的数据进行比较,很少用于非同类型数据之间的比较,equals一般应用同类型的对象之间进行比较,不能用于基本数据类型的比较。