Set:一个不包含重复元素的 collection。
更确切地讲,set 不包含满足 e1.equals(e2) 的元素对 e1 和 e2,并且最多包含一个 null 元素。
父接口:Collection
此实现是不同步的(不安全,效率高)
实现类:HashSet,TreeSet,LinkedHashSet
从以下版本开始: JDK 1.2
set特点:无序且唯一,只能添加一个null元素
遍历:for-each
Iterator 迭代器
无法使用for遍历,因为是无序的,所以没有get(i).
public static void main(String[] args) {
//1:创建一个Set集合
Set set = new HashSet<>();
//2:添加元素
set.add("a");
set.add("a");
set.add("b");
set.add("c");
set.add(null);
set.add(null);
System.out.println(set);
}
HashSet:此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。
它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。
特点:无序且唯一,允许使用null元素,但是只能有一个null元素
注意,此实现不是同步的。
父接口:List
父类:AbstractSet
子类:LinkedHashSet
从以下版本开始: 1.2
哈希表结构:是一种特殊的数据结构,数组+链表
数组保证了查询速度快
链表保证了增删速度快
底层是以键值对的形式存放数据
key–value
101–张三
102–张三
注意:key不能重复,但是value是可以重复的
hashSet:第一次添加元素的时候给了一个默认16的数组结构
HashSet特点
无序:底层要使用当前元素的hashCode和数组的长度-1做&运算,结果就是存放的数组的下表位置
唯一:
前提:判断对象是否相等,首先判断2个对象的hashCode以及equals是否相等,
如果相等,最后胡返回一个有值的对象,通过这个对象和null做==比较,结果为false,
所以重复的元素添加不进去
注意:如果数组下标中的链接节点超过8个,jdk1.8采用了新的二叉树结构数据结构,
什么时候数组扩容
第一次:元素个数超过12的时候,
第二次:元素个数超过24的时候,
依次类推…
HashSet去除重复的自定义对象
在java中属性值完全的相同的对象我们称为重复的对象
hashCode选用31的原理
1.基数要用质数
质数的特性(只有1和自己是因子)能够使得它和其他数相乘后得到的结果比其他方式更容易产成唯一性,也就是hash code值的冲突概率最小。
2.选择31是观测分布结果后的一个选择,不清楚原因,但的确有利。
public class Student {
private String name;
private Integer age;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Student(String name, Integer age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}
public Student() {
super();
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", sex=" + sex + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((age == null) ? 0 : age.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((sex == null) ? 0 : sex.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age == null) {
if (other.age != null)
return false;
} else if (!age.equals(other.age))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (sex == null) {
if (other.sex != null)
return false;
} else if (!sex.equals(other.sex))
return false;
return true;
}
}
public static void main(String[] args) {
//1:创建Student集合
HashSet hs = new HashSet<>();
//2:添加学生
hs.add(new Student(“张三”, 20, “男”));
hs.add(new Student(“李四”, 20, “女”));
hs.add(new Student(“王五”, 30, “男”));
hs.add(new Student(“张三”, 20, “男”));
System.out.println(new Integer(20).hashCode());
System.out.println("男".hashCode());
//3:遍历集合
for (Student stu : hs) {
System.out.println(stu);
}
System.out.println((24100577) ^ (24100577 >>> 16));
System.out.println(1023480028&15);
}
具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。
此实现与 HashSet 的不同之外在于,后者维护着一个运行于所有条目的双重链接列表。
父类:HashSet
父接口:Set
注意,此实现不是同步的。
从以下版本开始: 1.4
既能去除重复,而且还是有序的(添加顺序和迭代顺序一致)
public static void main(String[] args) {
LinkedHashSet lhs = new LinkedHashSet<>();
lhs.add(10);
lhs.add(20);
lhs.add(30);
lhs.add(40);
lhs.add(10);
System.out.println(lhs);
}
// 输出结果为:[10,20,30,40]
基于 TreeMap 的 NavigableSet 实现。
1 使用元素的自然顺序对元素进行排序
使用空构造器
TreeSet ts= new TreeSet<>();
2 或者根据创建 set 时提供的 Comparator 进行排序
TreeSet ts= new TreeSet<>(Comparator cp);
具体取决于使用的构造方法。
父接口:Set
注意,此实现不是同步的。
从以下版本开始: 1.2
注意:不允许添加null元素
TreeSet的特点:去重且排序
数组排序去重复
2个对象做比较结果为0,表示相等
2个对象做比较结果为-1,表示小于
2个对象做比较结果为1,表示大于
大的往右走,小的往左走,相等不进来
对一组数字按照从小到大排序,并且去除重复元素
10,20,500,-60,8,41,22,36,20
public class Demo {
public static void main(String[] args) {
TreeSet ts = new TreeSet<>();
ts.add(10);
ts.add(20);
ts.add(500);
ts.add(-60);
ts.add(8);
ts.add(41);
ts.add(22);
ts.add(36);
ts.add(20);
System.out.println(ts);
}
}
// 结果为[-60,8,10,20,22,36,41,500]
TreeSet 自定义对象排序且去重!!!
按照价格从小到大排序
创建学生对象
属性:学号,姓名,年龄,语文成绩,数学成绩,英语成绩
要求,对学生对象排序,按照总分排序
public class Product implements Comparable {
@Override
public int compareTo(Product s) {
//什么叫重复对象:所有属性的值完全相同,才成为同一个对象
//按照价格排序 主要条件
int num = (int)(this.getPrice()-s.getPrice());
//次要条件1 价格相同,编号不一定相同
int num1 = num==0?this.getId().compareTo(s.getId()):num;
//次要条件2 价格,编号相同,名称不一定相同
int num2 = num1==0?this.getName().compareTo(s.getName()):num1;
//次要条件3 价格,编号,名称相同,出产地不一定相同
int num3 = num2==0?this.getAddress().compareTo(s.getAddress()):num2;
return num3;
/*int num = (int)(this.getPrice()-s.getPrice());
//次要条件1 价格相同,编号不一定相同
num = num==0?this.getId().compareTo(s.getId()):num;
//次要条件2 价格,编号相同,名称不一定相同
num = num==0?this.getName().compareTo(s.getName()):num;
//次要条件3 价格,编号,名称相同,出产地不一定相同
num = num==0?this.getAddress().compareTo(s.getAddress()):num;
return num;*/
/*int n = (int)(this.getPrice()-s.getPrice());
if(n==0){
n = this.getId().compareTo(s.getId());
}
if(n==0){
n = this.getName().compareTo(s.getName());
}
if(n==0){
n = this.getAddress().compareTo(s.getAddress());
}
return n;*/
public class Test {
public static void main(String[] args) {
TreeSet tr=new TreeSet<>();
tr.add(new Student(01, "冯", 20, 90, 95, 98));
tr.add(new Student(02, "张", 21, 85, 75, 88));
tr.add(new Student(03, "罗", 18, 100, 100,100));
tr.add(new Student(04, "司", 20, 99, 65, 78));
System.out.println("编号\t姓名\t年龄\t语文成绩\t数学成绩\t英语成绩");
for (Student s : tr) {
System.out.println(s.getId()+"\t"+s.getName()+"\t"+
s.getAge()+"\t"+s.getChinese()+"\t"
+s.getMath()+"\t"+s.getEnglish());
}
}
}