Set集合(超详解)

2年前 (2022) 程序员胖胖胖虎阿
310 0 0

         回顾问题:

上一期我们讲了list集合,它的一个显著特点就是读取速度快,元素可重复,可以自动扩容!!!有一个问题,在上一期中,我们使用foreach去删除元素是会发现在两个相邻的同一样的元素中会发生执行错误,如果我们没有重复相邻的两个元素,再去删除,还是会有问题,但我们如果刚好删除的是倒数第二个元素,就可以正常删除,这是为什么呢,我们一起来看看。

下面的图都为源码:

array list的删除方法

大家首先看到这里的这个方法,在使用list进行foreach进行删除的时候我们就会进入到这里来,然后进行删除,那具体是怎么样的呢,其实在使用foreach进行删除的时候是调用的一个iterator来进行的,这个迭代器就是我们的array list的内部类中的iterator,它进入到这里之后会调用hasnext方法进行cursor进行一个和集合元素的长度进行比较,如果不相等就还有元素,然后接着往下走,调用next方法先去进行一个检查维护,那这个modCount是什么呢,它其实是我们的集合的大小,当我们集合元素大小发生变化是就会更着改变,例如,如果集合原本大小为5,此时插入一个元素,就变成了6.modCount也变成了6,减少一个变成4,modCount也变成了4。所以我们就会发现,在我们用foreach进行list的删除时这个检查约束过不不了就直接抛出异常了,而为什么倒数第二可以呢,以为删除它就变成倒数第一了,来不及检查约束就已经删除了,其实这也时一个特性,但它本质是一个bug。

array list的迭代器foreach所使用的

检查方法

检查方法

Set集合

特点:

1. 特点:无序,不重复

2. 遍历:foreach,迭代器

3.  扩容: 初始容量16,负载因子0.75,扩容增量1倍

 实现类

HashSet

特点:

1.它存储唯一元素并允许空值,依据对象的hashcode来确定该元素是否存在

2. 由HashMap支持

3. 不保持插入顺序

4. 非线程安全

5. 性能参数:初始容量,负载因子,默认值: 初始容量16,负载因子0.75,示例:new HashSet<>(20, 0.5f);

实例


	List<Integer> list = new ArrayList<Integer>();
	private Set<Integer> set = new HashSet<Integer>();

	@Before
	public void setup() {
		list.add(1);
		list.add(4);
		list.add(4);
		list.add(8);
		list.add(8);
		list.add(12);
		list.add(16);

		set.add(1);
		set.add(2);
		set.add(3);
		set.add(3);
		set.add(4);
		set.add(4);
		set.add(5);

	}

	@Test
	public void setdome01() {
		List<Integer> temp = new ArrayList<Integer>(new HashSet<Integer>(list));
		System.out.println(temp);
		// 结果:[16,1,4,8,12],hashset直接帮我们去重复了,因为set集合不可以出现重复的
		// 除了这种方法还有list的迭代器的去重复,还有最为死的for遍历,一个一个做判断删除

	}

//	HashSet其实就是一个皮包公司,都是委托
	@Test
	public void setdome02() {
		for (Integer ui : set) {
			System.out.println(ui);
		}
//		结果:12345;
//		可以看到,去重复和排序了
	}

	@Test
	public void setdome03() {
		Iterator<Integer> it = set.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
//			结果:12345
	}
//	可以看到,我们插入的到顺序是无序的,但我们输出的却是有序的,而set是无序的,
//	那为什么输出的有序呢,那是因为set的无序指的是插入的顺序是无序 ,而这的有序
//	是因为hashset的有序,我们常说的有序是指插入的顺序是有序的

TreeSet

1. 是一个包含有序的且没有重复元素的集合

2. 作用是提供有序的Set集合,自然排序或者根据提供的Comparator进行排序

3. TreeSet是基于TreeMap实现的

比较器

1.默认自然排序

1. 默认自然排序
   数据准备

 ts = new TreeSet<>();
		ts.add(1);
		ts.add(8);
		ts.add(7);
		ts.add(2);
		ts.add(4);
		ts.add(6);
		ts.add(3);


@Test
	public void setdome04() {
		Set<Student> set = new HashSet<Student>();
		set.add(new Student(1, "张三", 18));
		set.add(new Student(2, "李四", 19));
		set.add(new Student(3, "李凝", 20));
		set.add(new Student(4, "王三", 21));
		set.add(new Student(4, "王三", 21));
		set.add(new Student(5,"二虎",26));

		for (Student student : set) {
			System.out.println(student);
		}

	}

2.自定义排序

--1. 较器通过构造函数传入比

1. 较器通过构造函数传入比
TreeSet<Integer> tset = new TreeSet<Integer>(new Comparator<Integer>() {
			@Override
			public int compare(Integer o1, Integer o2) {
				// TODO Auto-generated method stub
				return o2 - o1;
			}
		});

2. 2. 实现排序接口

public class Student implements Comparable<Student>{
	
	private Integer sid;
	
	private String name;
	
	private int age;

	
	@Override
	public int compareTo(Student o) {
		// TODO Auto-generated method stub
		return o.getAge() - this.getAge();
	}

}



Student实体类

package com.zking.test;

public class Student implements Comparable<Student> {

	private Integer sid;

	private String sname;

	private int age;

	public Student(Integer sid, String sname, int age) {
		super();
		this.sid = sid;
		this.sname = sname;
		this.age = age;
	}

	public Integer getSid() {
		return sid;
	}

	public void setSid(Integer sid) {
		this.sid = sid;
	}

	public String getSname() {
		return sname;
	}

	public void setSname(String sname) {
		this.sname = sname;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((sid == null) ? 0 : sid.hashCode());
		result = prime * result + ((sname == null) ? 0 : sname.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 != other.age)
			return false;
		if (sid == null) {
			if (other.sid != null)
				return false;
		} else if (!sid.equals(other.sid))
			return false;
		if (sname == null) {
			if (other.sname != null)
				return false;
		} else if (!sname.equals(other.sname))
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "Student [sid=" + sid + ", sname=" + sname + ", age=" + age + "]";
	}

	@Override
	public int compareTo(Student o) {
		if (this.getAge() - o.getAge() == 0) {
			return this.getSid() - o.getSid();
		}
		return this.getAge() - o.getAge();
	}

}

总结:

set集合元素无放入顺序,且不可重复(注意:元素虽然无放入顺序,但是元素在Set中的位置是由该元素的HashCode决定的,其位置是固定的)。List支持for循环,也就是通过下标来遍历,也可以用迭代器,但是Set只能用迭代器,因为他无序,无法使用下标取值;Set:检索元素效率低,删除和插入效率高,插入和删除不会引起元素位置改变。

版权声明:程序员胖胖胖虎阿 发表于 2022年9月4日 下午7:32。
转载请注明:Set集合(超详解) | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...