抛砖引玉
int x = 10;
int y = 10;
String str1 = new String("abc");
String str2 = new String("abc");
String str3 = "abc";
String str4 = "abc";
System.out.println(x == y); // 输出?
System.out.println(str1 == str2); // 输出?
System.out.println(str1.equals(str2)); // 输出?
System.out.println(str3 == str4); // 输出?
System.out.println(str1 == str3); // 输出?
System.out.println(str1.equals(str3)); // 输出?
Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;
System.out.println(f1 == f2);// 输出?
System.out.println(f3 == f4);// 输出?
== & equals
==:对基本类型比较其值是否相等。对于引用类型比较其地址是否相同。
equals: 对所有类型,只比较其值是否相等。
对于新创建的自定义类,如果不重写equals(),则默认的equals()为
public boolean equals(Object obj){
return (this == obj);
}
也就是说,自定义类,如果没有重写equals方法,那么它的equals不能用于两个对象是否相等。它是不准确的,两个相等的对象也可能会返回false。
hashcode
关于hashcode方法本质可以作为一个精简的,不可靠的equals方法,它可以用于判断两个对象是否相等的问题。它的规则如下:
- 若两个对象相等,哈希值一定相等 (必须做到!!)
- 若哈希值不相等,则两个对象一定不相等 (必须做到)
注意这两条规则都是单向的,现在存在这样一个问题,两个对象哈希值相等,这时候是无法判断他们到底是否相等的。
为何需要hashcode呢? 这是由于equals开销太大,在Set或者Map容器中,需要快速判断容器内是否存在某个对象。他们使用到了哈希表原理,
他们的数据结构是:
- 一个长度合适的Table(数组)
- 当添加对象时,计算对象的hashcode()得到一个哈希值,再将这个哈希值变成一个数字下标i【(n - 1 ) % hash】
- 写数据时候就写入Table[i](桶的头结点)中,如果这个位置已经有元素,则调用equals方法,如果相同就不存,如果不同,则转到与之链接的下一个节点继续进行比较。
- 当一个桶中元素大于8个其数据结构会从链表转为红黑树。
关于 String 的一些问题
String 有字符串常量池的设定,所以说,对于相同的字符串,他们会在同一地址。(没有使用 new)
String str3 = "abc";
String str4 = "abc";
System.out.println(str3 == str4); //输出 true
当使用new 新建对象时,地址会不同。
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str1 == str2); //输出 false
关于Integer的一些问题
整型、char类型所对应的包装类,在自动装箱时,对于-128 至127之间的值会进行缓存处理。当然其目的就是提高效率。
缓存处理的原理为:如果数据在-128~127这个区间,那么在类加载时就已经为该区间的每个数值创建了对象,并将这256个对象存放到一个名为cache的数组中。每当自动装箱过程发生时(或者手动调用valueOf()时),就会先判断数据是否在该区间,如果在则直接获取数组中对应的包装类对象的引用,如果不在该区间,则会通过new调用包装类的构造方法来创建对象。
Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;
System.out.println(f1 == f2); // 输出true
System.out.println(f3 == f4); // 输出false