对于==号只需要考虑两种情况:
Integer a1=new Integer(4321); Integer a2=new Integer(4321); int a3=4321; System.out.println("a1==a2:"+(a1==a2));//结果为false,因为a1,a2是两个不同的对象,其堆中的地址值自然不同 System.out.println("a1==a3:"+(a1==a3));//结果为true,因为Java的自动拆箱机制,比较的是两个数值 System.out.println("a3==a1:"+(a3==a1));//结果为false,原因同上 Integer a4=4321; Integer a5=4321; /** * Integer a4=4321; * Integer a5=4321; * 相当于执行了 * Integer a4=Integer.valueOf (4321) ; * Integer a5=Integer.valueOf (4321) ; */ System.out.println("a4==a5:"+(a5==a4));//结果为false,相当于创建了两个对象,其地址自然不同 Integer a6=100; Integer a7=100; /** * 为什么这个又不一样呢 * 要根据装箱操作的源码 * public static Integer valueOf(int i) { * if (i >= -128 && i <= 127) * return IntegerCache.cache[i + 127]; * //如果i的值大于-128小于127则返回一个缓冲区中已存在的一个Integer对象 * return new Integer(i); * //否则返回 new 一个Integer 对象 * } * 可以看出如果是-128-127之间,装箱装的是同一个对象(为了节约内存) *所以如果是-128到127之间的装箱操作,装的都是同样的对象! */ System.out.println("a6==a7:"+(a6==a7));//为true Integer a8=128; Integer a9=128; System.out.println("a8==a9:"+(a8==a9));//为false Integer a10=-128; Integer a11=-128; System.out.println("a10==a11:"+(a10==a11));//为true a10=127; a11=127; System.out.println("a10==a11:"+(a10==a11));//为true /** * 注意,这种是直接生成对象的! * 没有进行装箱操作得到地址值,而是直接在堆创建生成的地址! * 所有不同的 */ Integer aa1=new Integer(1); Integer aa2=new Integer(1); System.out.println("aa1==aa2:"+(aa1==aa2));//为false
Java自动装箱拆箱机制的类型
String s1="12345"; String s2="12345"; String s3=new String("12345"); String s4=new String("12345"); /** * String s1=="xxx"这种字符串创建方式,并不是在堆中创建 * 为了节省空间,是在运行时常量池,也就是在方法区中创建 * s1和s2指向的是同一个地址 */ System.out.println("s1==s2:"+(s1==s2));//true System.out.println("s1==s3:"+(s1==s3));//false,s1指向的是常量池的地址,s3指向的堆中的地址 System.out.println("s3==s4:"+(s3==s4));//false,s3和s4指向的是堆中不同的地址,所以false
equals没有被重写就是比较地址,相当于===
原因:
equals用来比较的是两个对象的内容是否相等,由于所有的类都是继承自java.lang.Object类的,所以适用于所有对象,如果没有对该方法进行覆盖的话,调用的仍然是Object类中的方法,而Object中的equals方法返回的却是==的判断。
equals源码
显然java源码对String类进行了特殊处理,String的equals以及不是比较地址值了,而是比较字符串的内容了。
HashSet本身就重写了equals!
HashSet<Integer> set1=new HashSet(); HashSet<Integer> set2=new HashSet(); set1.add(1); set1.add(2); set2.add(1); set2.add(2); System.out.println(set1.equals(set2));//返回true!
而且比较有意义的是
HashSet底层实现是通过HashMap实现的
Array的equals用的是原生的
Integer[] array1={1,2,3}; Integer[] array2={1,2,3}; System.out.println(array1.equals(array2));//false //java.util.Arrays为我们提供了hashCode和euqals System.out.println(Arrays.equals(array1,array2));//true
但是java.util.Arrays为我们提供了hashCode和euqals,比较的是数组中的内部元素。
ps启发:
我们也可以学习这种方式
可以在不重写的方法下写一个通用类其中的方法进行计算hashcode和equals!
为什么重载hashCode方法?
答案:一般的地方不需要重载hashCode,只有当类需要放在HashTable、HashMap、HashSet等等hash结构的集合时才会 重载hashCode,那么为什么要重载hashCode呢?就HashMap来说,好比HashMap就是一个大内存块,里面有很多小内存块,小内存块 里面是一系列的对象,可以利用hashCode来查找小内存块hashCode%size(小内存块数量),所以当equal相等时,hashCode必 须相等,而且如果是object对象,必须重载hashCode和equal方法。
例如我们有对象A和对象B,现在重写了equals方法,让两者相等了,那我们用散列表HashSet存储了对象A,然后用set.contains(B),是查不到B存在的!
package com.company; public class Main { public static void main(String[] args) { // write your code here Person p1=new Person("l1",11,"男"); Person p2=new Person("l1",11,"男"); Person p3=new Person("l1",12,"男"); System.out.println(p1==p2);//false System.out.println(p1.equals(p2));//true System.out.println(p1.equals(p3));//false } } class Person{ String name; Integer age; String sex; @Override public int hashCode() { return 31*(this.name.hashCode()+31*this.age.hashCode()+31*(this.sex.hashCode())); } @Override public String toString() { return this.name+" "+this.age+" "+this.sex; } @Override public boolean equals(Object obj) { Person person1=(Person) obj; return this.hashCode()==person1.hashCode(); } public Person() { } public Person(String name, int age, String sex) { this.name = name; this.age = age; this.sex = sex; } }
outPut
false true false Process finished with exit code 0
Ps: 如果要用equal方法,请用object<不可能为空>.equal(object<可能为空>))
"target".equals(foo)