jvm中的堆内存和栈内存存储的数值或者类型的区别
1对于基础类型:变量的值和内容是一致的
2对于引用类型:变量的值在堆内存中,赋值的内容是一个地址,在栈内存中,指向堆内存
针对第二点举个例子:
String s = new String("s");
其中 s 是堆对象的引用,存储在堆中
其中 new String("s")是赋值的内容,是一个地址,存储在栈中
==
一般用于基础类型比较,比较堆中的地址,栈中的值是否相同
基础类型包括:
boolean
char
byte short int long
float double
equal
一般用于引用类型比较,比较的是 对 对象的引用是否相同,比较的是堆的内容是否相同
例子
String s1 = "Monday";
String s2 = "Monday";
s1==s1 //true
因为s1,s2的值均存放在常量池中,s1,s1在栈中存放常量池中位置相同
String s1 = "Monday";
String s2 = new String("Monday");
s1==s2; //false
他们值相同,但是堆中的位置不同
s1.equals(s2); //true
s2 引用的是s1所引用的对象,
为何比较对象需要重写equal
1通过比较对象的引用比较是否相等是得不到相等的结果的,因为俩个对象的引用是永远不会相等的;
2可以通过比较这俩个对象的属性判断是否相等
3重写equal的要求:
一般我们在设计一个类时,需要重写父类的equals方法,在重写这个方法时,需要按照以下几个规则设计:
(1)、自反性:对任意引用值X,x.equals(x)的返回值一定为true.
(2)、对称性:对于任何引用值x,y,当且仅当y.equals(x)返回值为true时,x.equals(y)的返回值一定为true;
(3)、传递性:如果x.equals(y)=true, y.equals(z)=true,则x.equals(z)=true
(4)、一致性:如果参与比较的对象没任何改变,则对象比较的结果也不应该有任何改变
(5)、非空性:任何非空的引用值X,x.equals(null)的返回值一定为false
为何重写equal要重写hashcode 1可能存在俩个对象相等,而hashcode不同的情况,在这种情况下存储到hsahmap种,根据key去查找,则找不到
2哈希碰撞:http://www.ruanyifeng.com/blog/2018/09/hash-collision-and-birthday-attack.html
如何重写hashcode 计算hashCode的注意事项:
1、不能包含equals方法中没有的字段,否则会导致相等的对象可能会有不同的哈希值。
(即对类中每一个重要字段,也就是影响对象的值的字段,也就是equals方法里有比较的字段,进行操作)
2、String对象和Bigdecimal对象已经重写了hashcode方法,这些类型的值可以直接用于重写hashcode方法;
3、result = 31 *result + (dishCode !=null ?dishCode.hashCode() : 0);,这里面为啥用个31来计算,而且很多人都是这么写的,这是因为31是个神奇的数字,任何数n*31都可以被jvm优化为(n<<5)-n,移位和减法的操作效率比乘法的操作效率高很多!
4、Google首席Java架构师Joshua Bloch在他的著作《Effective Java》中提出了一种简单通用的hashCode算法:
①初始化一个整形变量,为此变量赋予一个非零的常数值,比如int result = 17;
②如果是对象应用(例如有String类型的字段),如果equals方法中采取递归调用的比较方式,那么hashCode中同样采取递归调用hashCode的方式。否则需要为这个域计算一个范式,比如当这个域的值为null的时候(即 String a = null 时),那么hashCode值为0