equals与==的使用

equals与==的区别

1. equals是方法,==是操作符;
2. 对基本类型,int、long等进行判等,只能使用==,比较的是直接值(基本类型的值就是其数值);
3. 对引用类型,Integer、Long和String等进行判等,需要使用equals进行内容判等;
4. 引用类型的直接值是指针,使用==比较的是指针,也就是两个对象在内存中的地址,即比较它们是不是同一个对象,而不是对象的内容;
5. 比较值的内容,除了基本类型只能用==,其他类型都需要用equals。

 

Integer判等问题:

结论:比较Integer的值使用equals
复制代码
//例子1:值相等为true
Integer a = 127;//Integer.valueOf(127)
Integer b = 127;//Integer.valueOf(127)
log.info("{}", a ==b);//true
//编译器会把Integer a = 127转换为Integer.valueOf(127),这个转换在内部其实做了缓存,使得两个Integer指向同一个对象。
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

//例子2:值相等为false
Integer c = 128;//Integer.valueOf(128)
Integer d = 128;//Integer.valueOf(128)
log.info("{}", c ==d);//false
//默认情况下会缓存[-128, 127]的数值,为了包含128,添加JVM参数 -XX:AutoBoxCacheMax=1000,则情况和例子1一样为true

//例子3:第一个是缓存对象,第二个是新对象,不是一个对象
Integer e = 127; //Integer.valueOf(127)
Integer f = new Integer(127); //new instance
log.info("{}", e ==f);//false

//例子4:两个新对象,不是相同的对象
Integer g = new Integer(127); //new instance
Integer h = new Integer(127); //new instance
log.info("{}", g ==h);//false

//例子5:会先拆箱再与int值比较,数值相同true
Integer i = 128; //unbox
int j = 128;
log.info("{}", i ==j);//true
复制代码

 

String判等问题

复制代码
//例子1:直接用双引号声明的两个String对象指向常量池中的相同字符串
String a = "1";
String b = "1";
log.info("{}", a==b);//true
//Java字符串常量池机制:目的节省内存,使用""声明创建字符串对象时,JVM会对这个字符串进行检查,
//如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回;否则创建新的字符串对象,然后将这个引用放入字符串常量池,并返回该引用。
//例子2:new出的是不同的对象,对应的引用不同 String c = new String("2"); String d = new String("2"); log.info("{}", c==d);//false //例子3:.intern()方法会走常量池机制,该方法不可滥用,可能会产生性能问题(解决需要调整JVM参数:-XX:StringTableSize=1000)(-XX:+PrintStringTableStatistic可打印统计信息) String e = new String("3").intern(); String f = new String("3").intern(); log.info("{}", e==f);//true //例子4:equals对值内容判等 String g = new String("4"); String h = new String("4"); log.info("{}", g==h);//true
复制代码

 使用equals需要注意的情况

复制代码
//Object类中源码
public boolean equals(Object obj) {
    return (this == obj);
}

1. 考虑到性能,可以先进行指针判等,如果对象是同一个那么直接返回true;
2. 需要对另一方进行判空,空对象和自身进行比较,结果一定是false;
3. 需要判等两个对象的类型,如果类型不同,直接返回false;
4. 确保类型相同的情况下再进行类型强制转换,然后逐一判断所有字段。
如:

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Point that = (Point) o;
    return x == that.x && y == that.y;
}    
//其中instanceof进行类型检查规则是:你是该类或者是该类的子类;
//getClass获得类型信息采用==来进行检查是否相等的操作是严格的判断。不会存在继承方面的考虑;
复制代码

自定义类型时,与equals 保持一致性

一、自定义类型需要判等,equals和hashCode需要配对实现,通过idea快速生成或Lombok插件;
二、自定义类型需要比较,compareTo和equals、hashCode保持逻辑一致性;
三、因此,对于自定义类型,要实现Comparable,需要equals、hashCode、compareTo三者逻辑保持一致。

Lombok使用注意事项

1. Lombok的@Data注解会帮我们实现equals和hashCode方法
2. @EqualsAndHashCode.Exclude注解修饰的字段,会从equals和hashCode的实现中排除;
3. 类型之间有继承,@EqualsAndHashCode默认实现没有父类属性
4. @EqualsAndHashCode(callSuper = true)在类上添加开关,来覆盖默认行为,这样即实现了同时以子类和父类属性实现equals和hashCode方法(实际上调用了父类的equals和hashCode);
5. 阿里巴巴的Java规约插件可以避免这类低级错误:https://github.com/alibaba/p3c

 

posted @   白玉神驹  阅读(46)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示