目录
Java中的八大基本数据类型:byte、short、int、long、float、double、boolean、char。
String类型、还有Integer、Long等包装类型,都属于引用数据类型,也就是一个个对象。
==
1.基本类型比较时,==比较的是值。
int a = 127;
int b = 127;
System.out.println(a==b);//true
2.引用类型比较时,==比较的是对象的引用。
Integer等包装数据类型为例:
Integer i1 = new Integer(127);
Integer i2 = new Integer(127);
System.out.println(i1==i2);//false
String类型为例:
String s1 = new String("suvue");
String s2 = new String("suvue");
System.out.println(s1==s2);//false
普通对象为例:
@Data
class Suvue{
private String name;
public Suvue(String name) {
this.name = name;
}
}
public class Balabala {
public static void main(String[] args){
Suvue suvue1 = new Suvue("这是我的名字");
Suvue suvue2 = new Suvue("这是我的名字");
System.out.println(suvue1==suvue2);//false
}
}
3.Integer等包装数据类型中缓存池的作用。
先来看下面代码中的一个现象吧。
Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1==i2);//true
Integer i3 = -128;
Integer i4 = -128;
System.out.println(i3==i4);//true
看了代码很不解,包装类型用==比较,竟然返回的true!
这是因为在Integer、Long等包装类中,有一个可变大小的缓存池,默认的范围都是 -128~127。
来看下这个缓存池的源码吧!(篇幅有限只截取重要部分)
private static class IntegerCache {
static final int low = -128;
static final int high;
//我们说的缓存池就是下面这个东西
static final Integer cache[];
static {
// 池子的上限我们可以进行配置
int h = 127;
//...获取自定义上限值的代码(此处省略)
// 上限值不能小于127
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
创建一个缓存池很简单吧,底层其实就是一个int类型的数组而已,只不过可以自定义数组内元素值的上限嘛。
我们先来分析一下,像Integer i1 = 127;
这样的代码,i1为Integer类型,127为int类型,Integer与int又没有继承关系,一般情况下,这样的代码编译时会报错的!但是由于Java中的自动装箱机制,Java会自动将int类型转换为Integer类型,即:Integer i1 = Integer.valueOf(127);
那么我们来看下,调用Integer.valueOf()时,Integer的缓存池是怎么使用的吧!
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
解释下这段源码吧,当int类型的数值在缓存池的范围内(默认为-128~127)时,从缓存池中;不在这个范围内的话,就new一个对象返回。
所以我们测试代码中的数据127和-128都在缓存池内,这里以127为例,两次都取到数据都是缓存池中的127,所以比较的结果时true。
上文我们提到了自定义常量池的上限值,具体的做法请参照笔者的这篇博文 https://blog.csdn.net/weixin_45612794/article/details/100770028 这里就不多叙述了。
4.String数据类型中字符串常量池的作用。
先来看下这段测试代码吧!
String s1 = "suvue";
String s2 = "suvue";
System.out.println(s1==s2); //true
String s3 = "中国";
String s4 = "中国";
System.out.println(s3==s4); //true
上面代码为true的原因,比如
第一次执行String s1 = "suvue";
这段代码时,会去JVM的字符串常量池中查找,发现之前没有“suvue”这个字符串,那么会在字符串常量池中申请一块空间,新建一个"suvue"字符串并返回它在字符串常量池中的引用给s1。
当第二次执行String s2 = "suvue";
会去JVM的字符串常量池中查找,此时发现已经有了“suvue”这个字符串,那么直接返回它在字符串常量池中的引用给s2。
“==”比较对象时,比较的是否是同一对象的引用。此时发现s1和s2是同一个引用,那么打印的结果自然是true了。
2.equals()
2.1.普通对象
先看个测试代码吧
Balabala o1 = new Balabala();
Balabala o2 = new Balabala();
System.out.println(o1.equals(o2));//false
Java中所有的对象,都隐式的集成了Object类,所以一般情况下调用的都是Object的equals方法,我们看下它的代码实现吧!
public boolean equals(Object obj) {
return (this == obj);
}
我们看到,它的默认实现,其实调用的是==
。那么就不难理解为啥是false了。
2.1 Integer等包装类型对象
Integer i1 = new Integer(128);
Integer i2 = new Integer(128);
System.out.println(i1.equals(i2));//true
结果为true的原因,是因为Integer类重写了Object的equals方法,相当于比较的是两个Integer对象的int值。
来看下equals方法的源码实现吧!
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
代码很简单,我就不多解释了哈。
2.3 String对象
老规矩,先来看测试代码。
String s1=new String("suvue");
String s2=new String("suvue");
System.out.println(s1.equals(s2));//true
为true的原因也很简单,同样是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;
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对象的char数组,从头到尾都一直的话,就返回true了。
3.小结
1.当使用==
时,如果比较的是八大基本类型的值,直接看值是否相等;如果有任一方有new关键字
存在(比较的是对象),结果肯定是false了;如果是包装类型的话,首先要判断是否在缓存池中;如果是String类型的,因为有字符串常量池的存在,只要字面值一样,结果就是true。
2.当使用equals时,除了包装类型和String类之外,其他比较的都是对象的内存地址。
笔者可能总结的不太好,所以还是要多多理解与实战!