Set接口
Set接口概述
一个不包含重复元素的collection。
HashSet类实现了Set接口,线程不安全,效率高
HashSet类概述
不保证set的迭代顺序
特别是它不保证该顺序恒久不变。
HashSet如何保证元素唯一性
底层数据结构是哈希表(元素是链表的数组)
哈希表依赖于哈希值存储
添加功能底层依赖两个方法:
Set案例
案例存储字符串并遍历
import java.util.HashSet;
import java.util.Set;
public class SetTest1 {
public static void main(String[] args) {
//创建Set集合对象
Set set =new HashSet<>();
//向set集合添加元素
set.add('java');
set.add('hive');
set.add('spark');
set.add('flink');
set.add('flink');
set.add('bigdata');
set.add('hadoop');
//增强for循环遍历
for (String s:set){
System.out.println(s);
}
}
}
可以看出set集合是无序且不重复的
案例存储自定义对象并遍历
首先封装一个学生类(封装)
public class Student {
private String name;
private int age;
//无参,有参构造方法
public Student() {}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
//get方法
public String getName() {
return name;
}
public int getAge() {
return age;
}
//set方法
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
//toString方法
@Override
public String toString() {
return 'Student{' +
'name='' + name + ''' +
', age=' + age +
'}';
}
}
再创建集合存储学生对象遍历
import java.util.HashSet;
import java.util.Set;
public class SetTest2 {
public static void main(String[] args) {
//创建Set集合对象
Set set = new HashSet<>();
//创建学生对象
Student s1 =new Student('student1',20);
Student s2 =new Student('student2',17);
Student s3 =new Student('student3',22);
Student s4 =new Student('student4',20);
Student s5 =new Student('student1',20);
//向集合添加元素
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
set.add(s5);
//增强for循环遍历
for (Student s :set){
System.out.println(s.getName()+'-----'+s.getAge());
}
}
}
遍历后发现有重复的对象,这是因为HashSet中add()方法实际HashMap中的put方法,与hashCode()方法和equals()方法有关方法的源码),所以集合会不会去重取决与元素类中有没有重写hashCode()方法与equals()方法,而这里的元素类是Student类,Student类中没有重写这两个方法,所以调用Object父类中的equals()方法,而Object类中的equals()方法比较的是地址值,学生对象都是new出来的,所以地址值肯定不一样,所以集合认为这两个对象不同,就没有去重。
解决方法:在Student类中重写hashCode与equals方法
//直接快捷键 Alt+Insert 选hashcode和equals
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
HashSet类实现Set接口,而LinkedHashSet类继承自HashSet类也实现了Set接口。
线程不安全,效率高
元素有序唯一
由链表保证元素有序
由哈希表保证元素唯一
LinkedHashSet集合案例
例:存储并遍历字符串
import java.util.LinkedHashSet;
public class LinkedHashSetTest1 {
public static void main(String[] args) {
//创建集合对象
LinkedHashSet set = new LinkedHashSet<>();
//向集合添加元素
set.add('java');
set.add('hive');
set.add('java');
set.add('spark');
set.add('bigdata');
//增强for循环遍历
for (String s:set){
System.out.println(s);
}
}
}
线程不安全的,效率高
TreeSet类概述
元素唯两种排序方式:
使用元素的自然顺序对元素进行排序
或者根据创建set时提供的Comparator进行排序
具体取决于使用的构造方法。
TreeSet是如何保证元素的排序和唯一性的
底层数据结构是红黑树(红黑树是一种自平衡的二叉树)
TreeSet案例
例TreeSet集合存储数字
import java.util.TreeSet;
public class TreeSetTest1 {
public static void main(String[] args) {
//创建TreeSet集合对象
TreeSet set = new TreeSet<>(); //集合只能存放引用数据类型,不能存放基础数据类型,Integer是int类的封装类
//向集合添加元素
set.add(33);
set.add(2);
set.add(45);
set.add(53);
set.add(2);
set.add(78);
//增强for循环遍历
for (Integer i :set){
System.out.println(i);
}
}
}
可以看出结果中元素是唯一且有序的
部分源码片:
例TreeSet存储自定义对象
首先封装一个公共的学生类
再创建TreeSet集合存储对象测试
import java.util.TreeSet;
public class TreeSetTest2 {
public static void main(String[] args) {
//创建集合对象
TreeSet set = new TreeSet<>();
//创建学生对象
Student s1 =new Student('we2323',23);
Student s2 =new Student('df532',26);
Student s3 =new Student('fg3435',16);
Student s4 =new Student('df532',26);
Student s5 =new Student('dsf24124',20);
//向集合添加元素
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
set.add(s5);
//遍历
for (Student s:set){
System.out.println(s);
}
}
}
然后就报错了,因为这里也是无参构造创建的集合,走的也是自然排序,而自定义的Student类中并没有实现Comparable接口,更没有向下转型,所以报类型转换异常的错误。
解决方法:修改Student类实现Comparade接口
再重写ComparaTo方法,修改返回值,按自定义方法排序,如按年龄排序
@Override
public int compareTo(Student o) {
//比较年龄大小
int i1=this.age-o.age;
//年龄一样姓名不一定一样
int i2= i1==0?this.name.compareTo(o.name):i1; //三目运算判断当年龄一样时,姓名是否一样,一样直接返回i1,不一样就继续按姓名排序
return i2; //返回值决定元素位置,小于0的放左边,大于0放右边,等于0就重复了去重
}
例利用TreeSet创建对象时带参数的构造方法进行比较器排序
有参构造源码部分片:
首先封装一个学生类
public class Student {
private String name;
private int age;
//无参,有参构造方法
public Student() {}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
//get方法
public String getName() {
return name;
}
public int getAge() {
return age;
}
//set方法
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
//toString方法
@Override
public String toString() {
return 'Student{' +
'name='' + name + ''' +
', age=' + age +
'}';
}
}
然后创建一个类去实现Comparator接口,重写compara方法
import java.util.Comparator;
public class ComparableTest implements Comparator {
//重写compara方法
@Override
public int compare(Student o1, Student o2) { //这里面自定义你的排序方法,我这里按名字长度为主排序
//先比较名字长度
int i1=o1.getName().length()-o2.getName().length();
//若姓名长度一样,比较姓名内容
int i2= i1==0?o1.getName().compareTo(o2.getName()):i1; //姓名长度不一样直i1赋给i2
//若姓名内容也一样,比较年龄
int i3= i2==0?o1.getAge()-o2.getAge():i2;
return i3;//返回值决定元素位置,小于0的放左边,大于0放右边,等于0就重复了去重
}
}
最后用有参构造创建集合,把自定义的类放进去测试
import java.util.TreeSet;
public class TreeSetTest3 {
public static void main(String[] args) {
//创建自定义类的对象
ComparableTest co = new ComparableTest();
//创建集合
TreeSet set = new TreeSet<>(co); //把自定义类的对象放进去
//创建学生对象并添加
Student s1 =new Student('qq1224',24);
Student s2 =new Student('qq1224',26);
Student s3 =new Student('rw333',24);
Student s4 =new Student('ree434343',26);
Student s5 =new Student('ere2232',16);
Student s6 =new Student('qq1224',24);
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
set.add(s5);
set.add(s6);
//遍历
for (Student s :set){
System.out.println(s);
}
}
}
可以看到结果已经按名字长度为主排序了,也去重了,这就是比较器排序。
TreeSet set = new TreeSet<>(new Comparator() { //这样创建对象就行了
@Override
public int compare(Student o1, Student o2) { //里面的方法一样
int i1=o1.getName().length()-o2.getName().length();
int i2= i1==0?o1.getName().compareTo(o2.getName()):i1;
int i3 = i2==0?o1.getAge()-o2.getAge():i2;
return i3;
}
});
比较方法跟原来一样,就是直接在构造时new了一个类实现Comparator接口。
文章为作者独立观点,不代表股票配资公司观点
卸妆水2023-06-16
股票我没什么看法没有左右市场的资金量中医的话这波疫情我收益良多小孩太小医院很多药都不敢用中医开了个桔梗甘草汤挺好用的,西医其实对普通人来说真的是好东西,虽然有些类似抗生素的东西副作用不小,但是给普通人看病成本降了很多,真正好的中药光药材就不是普通人的消费水平了,各有各的消费群体,都是好东西踩一捧一没什么必要红尘听语2022-12-03
不要小看股票,股票知道某些公司是假的,比如乐视,知道某些公司没那么大前景,比如中车,但是基金经理就是要进来抱团。股票比他们强多了