在Java中,equals和==是两种用于比较对象的操作符,但它们的行为和用途有所不同。
== 操作符:
== 操作符用于比较两个对象的引用是否相等,即它们是否指向同一个内存地址。
对于基本数据类型(如int、double、char等),== 比较的是它们的值是否相等。
对于引用数据类型(如对象、数组等),== 比较的是它们的引用是否指向同一个对象。
equals 方法:
equals 方法是Object类中的一个方法,用于比较两个对象的内容是否相等。
在自定义类中,通常需要重写equals方法,以提供自定义的对象比较逻辑。
如果没有重写equals方法,默认情况下,它的行为与==操作符相同,即比较引用是否相等。
这里需要知道大概的内存分布
Java提供的所有类中,绝大多数类都重写了equals()方法,equals方法进行了重写则是用来比较指向的对象所存储的内容是否相等
Integer a= 127 与 Integer b = 127 相等吗对于对象引用类型: == 比较的是对象的内存地址。对于基本数据类型: == 比较的是值。如果整型字面量的值在 -128 到 127 之间,那么自动装箱时不会 new新的 Integer 对象,而是直接引用常量池中的 Integer 对象,超过范围 a1==b1 的结果是 false
Integer a = 1,Integer f = new Integer(1),int c = 1有什么区别
int c = 1:
int
是基本数据类型,直接存储数值 1 在栈内存中,在程序运行时,其值直接存储在栈空间中,访问和操作速度较快。
Integer a = 1:
Integer变量指向的是 java 常量池中的对象
Integer
是int
的包装类,属于引用数据类型。当使用Integer a = 1
这种方式赋值时,Java 会自动进行装箱操作,实际上是调用了Integer.valueOf(1)
方法,将基本数据类型int
的值 1 转换为Integer
对象。这个Integer
对象可能会被缓存在Integer
类的内部缓存中(缓存范围一般是 - 128 到 127),如果在这个范围内,会直接返回缓存中的对象,否则会创建新的Integer
对象并存储在堆内存中,而变量a
存储的是这个Integer
对象的引用,存放在栈内存中。- 当使用
==
比较两个Integer
对象时,如果两个对象在缓存范围内且是同一个对象,则返回true
;否则,即使两个对象的值相等,==
也会返回false
。例如Integer a = 1; Integer b = 1; System.out.println(a == b);
会返回true
,但如果Integer a = 128; Integer b = 128; System.out.println(a == b);
则会返回false
。如果要比较两个Integer
对象的值是否相等,应该使用equals()
方法,如System.out.println(a.equals(b));
Integer f = new Integer(1)
new Integer() 的变量指向堆中新建的对象,两者在内存中的地址不同
- 显式地使用
new
关键字创建一个新的Integer
对象,无论传入的值是否在缓存范围内,都会在堆内存中创建一个新的Integer
对象,然后变量f
存储的是这个新创建的Integer
对象在堆内存中的引用,该引用存放在栈内存中。- 因为每次都是新创建的对象,所以使用
==
比较时,除非是同一个对象引用,否则总是返回false
。同样需要使用equals()
方法来比较值是否相等
Integer a = 1; // 这里会自动装箱 Integer b = 1; Integer f = new Integer(1); Integer g = new Integer(1); int c = 1; int d = 1;
System.out.println(a==d); // a会自动拆箱 System.out.println(a.equals(d)); // d会自动装修 System.out.println(a == b); // System.out.println(a.equals(b)); // true System.out.println(f == a); // false System.out.println(f == c); // true System.out.println(f.equals(c)); System.out.println(f.equals(a)); System.out.println(f.equals(g));
判断下列的输出结果 String aaa = new String("ab"); // a 为一个引用 String bbb= new String("ab"); // b为另一个引用,对象的内容一样 String aa = "ab"; // 放在常量池中 String bb = "ab"; // 从常量池中查找 System.out.println(aa.equals(aaa)); System.out.println(aa==bb); System.out.println(aa.equals(bb)); System.out.println(aaa==bb); System.out.println(aaa==bbb); System.out.println(aaa.equals(bbb));
hashCode()介绍
一个对象肯定有物理地址,对象的物理地址跟这个hashcode地址不一样,hashcode代表对象的地址说的是对象在hash表中的位置,物理地址说的对象存放在内存中的地址,那么对象如何得到hashcode呢?
通过对象的内部地址(也就是物理地址)转换成一个整数,然后该整数通过hash函数的算法就得到了hashcode。所以,hashcode是什么呢?就是在hash表中对应的位置。
从hash表中的查找效率更高!!!!
简单来说
如果两个对象的hashCode()相等,那么他们的equals()不一定相等。
如果两个对象的equals()相等,那么他们的hashCode()必定相等。因为equals可以看作比较的是内存中的数据
hashCode是把内存中的数据映射到hash表中,表中的数据相等,内存中不一定相等
内存中的相等,表中的一定相等
在没有 hashCode的情况下,在 Set集合中存储1000个对象的话需要用 equals来比较对象的值是否重复, 我们知道 Set是不允许重复对象存在的, 那么当这一千个对象都不重复的情况下, 第1000个对象的存储需要调用1000次 equals去进行比较,这是非常低效的。
而hashCode能解决这种问题,对象的存储不再是顺序存放,而是通过 hashCode直接计算出存储的位置, (可以理解为内存地址,虽然并不是) 之后新对象在存储的时候如果 hashCode跟之前的没有重复则直接存储,如果重复了则用 equals()校验是否相等, 如果不相等的话,以 HashMap作为例子,默认是在同一个地址上用链表存储起来新的对象,