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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通