本文主要是介绍Java-Set集合,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
Set相关集合
- public interface Set extends Collection不包含重复元素的集合,元素唯一且无序(存储和取出的顺序不一致)。Set集合中的元素为什么不会重复?看源码
源码如下:
public interface Set<E> extends Collection<E> {
boolean add(E e);
}
public class HashSet<E> extends AbstractSet<E> implements Set<E>{
private static final Object PRESENT = new Object();
private transient HashMap<E,Object> map;
public boolean add(E e) {
//e -- "hello"
//PRESENT -- new Object()
return map.put(e, PRESENT)==null;
}
}
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>{
//key -- "hello"
//value -- new Object()
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
//这个方法可以简单理解为调用元素类中的hashCode()方法计算哈希值
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {
//简单理解为哈希表中存储的是一个一个的节点数组
Node<K,V>[] tab;
Node<K,V> p;
int n, i;
//判断哈希表是否已经做完初始化,如果发现没有做初始化,就在这里给它做初始化
if ((tab = table) == null || (n = tab.length) == 0){
n = (tab = resize()).length;
}
//根据元素对象计算好的哈希值再进行一次与运算,计算出来的是该元素在哈希表中存储的位置
//如果这个位置上是null,说明该位置上暂且是没有元素的,可以进行存储
//创建新的节点,在该位置上存储元素
//分析到这一步,发现存储的过程是与元素类中的hashCode()结果相关的。
if ((p = tab[i = (n - 1) & hash]) == null){
tab[i] = newNode(hash, key, value, null);
}else {
Node<K,V> e;
K k;
//看到这里我们得出判断元素的哈希值是否一样并且判断元素的内容是否一样
//根据元素类中的equals()方法进行判断
//如果哈希值一样说明存储的位置一样
//如果equals()比较的结果一样,说明内容一样(前提是元素类中重写了equals方法,否则调用的是父类Object的equals方法)
//这样的话,比较的是地址值
//如果都一样,不搭理他,从现象上来看,就是没有赋值
//看到这里,我们其实没有必要再往后看了
//已经知道了代码中add()方法,其实是和元素类中的hashCode()和equals()方法有关
//会不会去重取决于该元素类中有没有重写hashCode()和equals()方法
if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
}
传入引用类型的对象:必须重写哈希和equals方法
package com.bigdat.java.day21;
import java.util.HashSet;
/*
在 set 中添加学生对象并调用
*/
public class SetDemo2 {
public static void main(String[] args) {
//创建学生类集合
HashSet<Student> stu = new HashSet<>();
//创建学生类对象
Student s1 = new Student("罗伯特",43);
Student s2 = new Student("基督伯爵",23);
Student s3 = new Student("罗伯特",43);
Student s4 = new Student("爱丽丝",13);
Student s5 = new Student("阿涛",43);
//向集合中添加学生
stu.add(s1);
stu.add(s2);
stu.add(s3);
stu.add(s4);
stu.add(s5);
//打印一下集合
System.out.println(stu);
System.out.println("==================================");
//利用增强 for 循环遍历集合
for(Student s:stu){
System.out.println(s);
//第一次遍历由于学生类中还没有重写哈希表和equals 方法
//所以结果为:没有去重
//第二次重写了之后达到了去重的效果 而且是无序的
}
}
}
学生类对象代码:
package com.bigdat.java.day21;
public class Student2 implements Comparable<Student2>{
private String name;
private int age;
public Student2() {
}
public Student2(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(Student2 o) {
// int i = this.name.compareTo(o.getName());
// int i2 = (i == 0)?this.age-o.age:i;
int i = o.age-this.age;
int i2 = (i==0)?this.name.compareTo(o.name):i;
return i2;
}
@Override
public String toString() {
return "Student2{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
这篇关于Java-Set集合的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!