1.集合
集合体系结构
起源:Collection
在其可使用的方法中就可看出,该集合无索引
List–在Collection的基础上增加了索引
其中ArrayList为List的数组实现类,LinkedList为List的链表实现类
Set–在Collection的基础上增加了不可重复的约束
其都是通过哈希表的方法来判断是否重复,其中LinkedHashSet继承了HashSet实现了存取有序,TreeSet则可将Comparable传入构造器使得其中元素按Comparable的规则排序。
HashCode&Equanls
先看一个约定:被equals判为相同的两个对象产生的哈希值必须相同。
哈希值
哈希值是啥?它不能做为对象的唯一标识,即不能当对象的身份证用,所以多个对象可能用着同一个哈希值。那还要这玩意有啥用?
有用!主要是给哈希表用的。哈希表在存储对象时会根据对象的哈希值来计算对象要存储的下标。
哈希表
了解一下哈希表:
先通过哈希值计算得下标,若下标处无对象则存储,有对象则比较:
可以看到,有了哈希值之后可以很方便的通过其计算下标来提高效率,否则只能将要存的对象整表遍历的去比较equals。
约定的作用:
所以我们可以先用哈希值去判断对象是否相同,若哈希值判断不了则再用equals判断,可以提高判断的效率。
为什么重写equals必须重写hashcode
就是为了满足约定:被equals判为相同的两个对象产生的哈希值必须相同。
不重写:
public class TestEquHash { // 测试类,重写了equals 没重写 hashCode
private String s;
public TestEquHash(String s) {this.s = s;}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TestEquHash that = (TestEquHash) o;
return Objects.equals(s, that.s);
}
}
结果:
class Te {
public static void main(String[] args) {
TestEquHash te1 = new TestEquHash("abc");
TestEquHash te2 = new TestEquHash("abc");
System.out.println(te1.equals(te2)); // 重写了equals 比值 返回 true
Map map = new HashMap();
map.put(te1, 111); // 由于没有重写 hashCode 方法 ,te1和te2 的 hashCode不同
map.put(te2, 222); // 两者存储在哈希表的不同下标位置,但他们的键值是相等的 都是 “abc” 与键值唯一冲突
System.out.println(map.get(te1)); // 输出 111
System.out.println(map.get(te2)); // 输出 222
}
}
重写:
public class TestEquHash { // 测试类,重写了equals 和 hashCode
private String s;
public TestEquHash(String s) {this.s = s;}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TestEquHash that = (TestEquHash) o;
return Objects.equals(s, that.s);
}
@Override
public int hashCode() {
return Objects.hash(s);
}
}
结果:
class Te {
public static void main(String[] args) {
TestEquHash te1 = new TestEquHash("abc");
TestEquHash te2 = new TestEquHash("abc");
System.out.println(te1.equals(te2)); // 重写了equals 比值 返回 true
Map map = new HashMap();
map.put(te1, 111); // 由于重写了 hashCode 方法 ,te1 te2 的 hashCode相同
map.put(te2, 222); // 两者会存储在哈希表同一下标位置,再加上它们的键值是相等的,都是 “abc”,所以value会被覆盖,保证了键值的唯一性
System.out.println(map.get(te1)); // 输出 222
System.out.println(map.get(te2)); // 输出 222
}
}
具体实现
问题:
假如对象Obj有三个字段:A,B,C。现在要求A,B字段相同的对象就是同一个对象。
解决:
- 重写equals方法,当两个对象的A,B都相同时返回true,否则返回false
- 重写hashcode方法(想办法满足约束),将A,B两个字段送入Object.hash()方法中生成哈希值并返回,使得当对象A,B字段相同时哈希值就一定相同,即equals判断为true时哈希值相同