学习集合Set

List和Set的区別

Collection
          |--List
          有序(存储顺序和取出顺序一致),可重复
          |--Set
          无序(存储顺序和取出顺序不一致),唯一
 
1) HashSet:它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。
                        注意:虽然Set集合的元素无序,但是,作为集合来说,它肯定有它自己的存储顺序,
                        而你的顺序恰好和它的存储顺序一致,这代表不了有序,你可以多存储一些数据,就能看到效果。

2) LinkedHashSet:底层数据结构由哈希表和链表组成。
 哈希表保证元素的唯一性。
 链表保证元素有素。(存储和取出是一致)

3)TreeSet:TreeSet集合的特点:排序和唯一

      能够对元素按照某种规则进行排序。
                  排序有两种方式
                              A:自然排序
                              B:比较器排序
      通过观察TreeSet的add()方法,我们知道最终要看TreeMap的put()方法。
                  
  
  


问题一:它們分別是如何保证元素的唯一性呢?

1)HashSet
 通过查看add方法的源码,我们知道这个方法底层依赖 两个方法:hashCode()和equals()
 步骤:
         首先比较哈希值
         如果相同,继续走,比较地址值或者走equals()
         如果不同,  就直接添加到集合中    
 按照方法的步骤来说:    
         先看hashCode()值是否相同
         相同:继续走equals()方法
         返回true: 说明元素重复,就不添加
         返回false:说明元素不重复,就添加到集合
         不同:就直接把元素添加到集合
 如果类没有重写这两个方法,默认使用的Object()。一般来说不同相同。
 而String类重写了hashCode()和equals()方法,所以,它就可以把内容相同的字符串去掉。只留下一个。

2)TreeSet

①如果new TreeSet的时候使用的是无参构造方法,底层实现如下

public TreeSet() {
       this(new TreeMap<E,Object>());//调用本类中封装的另一个带参构造
}

//NavigableMap是一个接口,TreeMap是实现了NavigableMap接口的类
TreeSet(NavigableMap<E,Object> m) {
       this.m = m;
}

private transient NavigableMap<E,Object> m;


//当调用add()方法的时候,实际是调用了TreeMap对象的put()方法
//put()通过compare()比较add()传进来的对象与集合中元素
public boolean add(E e) {
        return m.put(e, PRESENT)==null;
}

当调用add()方法的时候,实际是真正的比较是依赖于元素的compareTo()方法,而这个方法是定义在 Comparable里面的。所以,你要想重写该方法,就必须是先 Comparable接口。这个接口表示的就是自然排序。

②如果使用的是带参构造方法,需要传进一个实现了comparator接口的具体类对象或者匿名内部类作为形参。

实现了comparator接口的具体类中重写了compare()方法,以compare()方法对元素进行判断是否相同。

public TreeSet(Comparator<? super E> comparator) {
        this(new TreeMap<>(comparator));
}

举例代码:

MyComparator :

import java.util.Comparator;

public class MyComparator implements Comparator<Student> {

	@Override
	public int compare(Student s1, Student s2) {
		// int num = this.name.length() - s.name.length();
		// this -- s1
		// s -- s2
		// 姓名长度
		int num = s1.getName().length() - s2.getName().length();
		// 姓名内容
		int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
		// 年龄
		int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
		return num3;
	}

}

Student:

public class Student {
	private String name;
	private int age;

	public Student() {
		super();
	}

	public Student(String name, int age) {
		super();
		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;
	}
}

main:

public class TreeSetDemo {
	public static void main(String[] args) {
		// 创建集合对象
		// TreeSet<Student> ts = new TreeSet<Student>(); //自然排序
		// public TreeSet(Comparator comparator) //比较器排序
		// TreeSet<Student> ts = new TreeSet<Student>(new MyComparator());

		// 如果一个方法的参数是接口,那么真正要的是接口的实现类的对象
		// 而匿名内部类就可以实现这个东西
		TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
			@Override
			public int compare(Student s1, Student s2) {
				// 姓名长度
				int num = s1.getName().length() - s2.getName().length();
				// 姓名内容
				int num2 = num == 0 ? s1.getName().compareTo(s2.getName())
						: num;
				// 年龄
				int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
				return num3;
			}
		});

		// 创建元素
		Student s1 = new Student("linqingxia", 27);
		Student s2 = new Student("zhangguorong", 29);
		Student s3 = new Student("wanglihong", 23);
		Student s4 = new Student("linqingxia", 27);
		Student s5 = new Student("liushishi", 22);
		Student s6 = new Student("wuqilong", 40);
		Student s7 = new Student("fengqingy", 22);
		Student s8 = new Student("linqingxia", 29);

		// 添加元素
		ts.add(s1);
		ts.add(s2);
		ts.add(s3);
		ts.add(s4);
		ts.add(s5);
		ts.add(s6);
		ts.add(s7);
		ts.add(s8);

		// 遍历
		for (Student s : ts) {
			System.out.println(s.getName() + "---" + s.getAge());
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值