Set集合的学习

Set集合和List集合的区别?
  Set集合:不允许元素重复,唯一的(元素可以为null) ,不能保证迭代的顺序恒久不变(底层哈希表和hascode)
    无序(存储和取出不一致)

  List:允许元素重复,并且存储特点:有序性(存储和取出一致)

我们可通过一段代码来了解Set集合的这个特点

public static void main(String[] args) {
		
		//创建Set集合对象,子实现类:HashSet集合
		Set<String> set = new HashSet<String>();
		
		//添加元素
		set.add("hello") ;
		set.add("java") ;
		set.add("world") ;
		//看他的唯一性,多存储一些元素
		set.add("hello") ;
		set.add("java") ;
		set.add("world") ;
		//遍历
		for(String s: set) {
			System.out.println(s);
		}
	}
}//java
//world
//hello

我们可以看到,输出结果既没有重复的,顺序也不是我们录入的顺序。

对此,我们又有了一个新发现,即Set集合存储元素的时候,可以保证元素的唯一性,原因什么?

对此我们可以通过看它的源码学习:
    HashSet集合的add方法底层依赖于双列集合HashMap,它依赖于两个方法,HashCode()方法和equals()方法
  先比较字符串的HashCode()码值是否一样,再比较equals()方法
      如果hasCode码值一样,还要比较内容是否相同,由于存储String类型,所以重写了equals()方法

 String本身重写了equals方法,所以不需要再重写了。

 set集合存储自定义对象并遍历

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;
	}


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

public static void main(String[] args) {
			Set<Student> set = new HashSet<Student>() ;
			
			//创建学生对象
			Student s1 = new Student("高圆圆", 27) ;
			Student s2 = new Student("高圆圆", 28) ;
			Student s3 = new Student("文章", 30) ;
			Student s4 = new Student("马伊琍", 39) ;
			Student s5 = new Student("高圆圆", 27) ;
			
			//存储到集合中
			set.add(s1) ;
			set.add(s2) ;
			set.add(s3) ;
			set.add(s4) ;
			set.add(s5) ;
			
			//遍历
			for(Student s : set) {
				System.out.println(s.getName()+"---"+s.getAge());
			}
		}
}

如果在开发中,元素唯一性,并且还要保证元素有序(存储和取出一致),使用LinkedHashSet集合

 如果开发中要使用集合排序的问题,使用TreeSet集合(红黑树结构)。
  自然排序
选择器排序
 
LinkedHashSet集合:
  底层是一种链接列表和哈希表组成
可以保证元素的唯一性,是由哈希表决定的(hashCode()和equals())

  可以保证元素的迭代顺序一致(有序),存储和取出一致,是由链表决定。

public static void main(String[] args) {
		
		//创建LinkedHashSet集合对象
		LinkedHashSet<String> link = new LinkedHashSet<String>() ;
		
		//添加元素
		link.add("hello") ;
		link.add("java") ;
		link.add("world") ;
		link.add("world") ;
		link.add("world") ;
		link.add("java") ;
		//增强for遍历
		for(String s: link) {
			System.out.println(s);
		}
	}//hello
        //java
        //world
TreeSet集合模拟情况下是通过自然顺序对集合中的元素排序

TreeSet:
   可以保证元素唯一并且元素排序(Integer类型的元素自然升序)
  自然排序
比较器排序
 
 

 给TreeSet集合存储以下元素:20,23,22,18,17,19,24,21..

我们可以看下面的代码

public static void main(String[] args) {
		//创建一个集合对象TreeSet集合对象
		TreeSet<Integer> ts = new TreeSet<Integer>() ;
		
		//给集合中存储元素
		ts.add(20) ;		//add()方法底层的源码是一个Map接口实例
		ts.add(22) ;
		ts.add(18) ;
		ts.add(23) ;
		ts.add(24) ;
		ts.add(17) ;
		ts.add(19) ;
		ts.add(18) ;
		ts.add(21) ;
		
		//遍历
		for(Integer i : ts) {
			System.out.print(i +" ");
		}
	}

TreeSet集合的构造方式不同,使用的排序也不同
  自然排序:自定义的类实现Compareable接口,然后创建TreeSet对象,通过无参构造形式创建对象
  比较器排序 :public TreeSet(Comparator<E> comparator)
 
两种方式:
  1)自定义一个类,该类实现Comparator接口,重写Comparator接口中的compare()方法
2)直接使用接口匿名内部类的方式实现

TreeSet集合保证元素唯一,是看返回值是否为0 
保证元素进行排序,两种排序方式


我们先看自然排序。

做这样一个练习:

需求:使用TreeSet集合存储自定义对象(Student类型),并遍历!

按照学生的年龄从小到大进行排序 (主要条件)
  
唯一性:

若成员变量的值一样则认为是同一个对象

//对于自定义的类型,要实现自然排序,必须自定义的类型必须实现Comparable
//实现接口中的方法,compareTo() :比较方法
public class Student  implements Comparable<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;
	}

	@Override
	public int compareTo(Student s) {	//源码 cmp = k.compareTo(t.key)
		//return 0;
		//按照某种规则,前提必须有这规则
		//主要条件:按照年龄从小到大
		int num  = this.age - s.age ; //如果年龄相等,不一定是同一个人
		//需要自己分析次要条件;
		//年龄相同,姓名的内容不一定相同,比较姓名
		int num2 = num==0 ? this.name.compareTo(s.getName()) : num ;
		return num2 ;
	}
}
public static void main(String[] args) {
		//创建TreeSet集合对象
		TreeSet<Student> ts  = new TreeSet<Student>() ;//无参构造的方式自然排序
		
		//创建学生对象
		Student s1 = new Student("gaoyuanyuan",27) ;	
		Student s2 = new Student("liushishi",38) ;
		Student s3 = new Student("gaoyuanyuan",28) ;
		Student s4 = new Student("wanglihong",35) ;
		Student s5 = new Student("wanglihong",30) ;
		Student s6 = new Student("fengqingy",38) ;
		Student s7 = new Student("gaoyuanyuan",27) ;
		//java.lang.ClassCastException: org.westos_03.Student cannot be cast to java.lang.Comparable
		ts.add(s1) ;
		ts.add(s2) ;
		ts.add(s3) ;
		ts.add(s4) ;
		ts.add(s5) ;
		ts.add(s6) ;
		ts.add(s7) ;
		//遍历
		for(Student s:ts) {
			System.out.println(s.getName()+"---"+s.getAge());
		}
	}//gaoyuanyuan---27
         //gaoyuanyuan---28
        //wanglihong---30
        //wanglihong---35
        //fengqingy---38
        //liushishi---38

我们可以看到是按照年龄从小到大排列的,也可以按照姓名的长度进行排列,我们看一下代码。

public class Student implements Comparable<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;
	}
	
	//TreeSet集合保证元素的唯一性,看返回值是否为0
	@Override
	public int compareTo(Student s) {
		
		//按照姓名的长度进行比较(默认从小到大)
		int num = this.getName().length() - s.getName().length() ;
		
		//如果姓名的长度一样,还要比较他们的内容是否相同
		int num2 = num == 0 ?	this.getName().compareTo(s.getName()) :num ;
		
		//如果姓名长度和姓名的内容都一致,也不能保证就是同一个人,还要比较年龄
		int num3 = num2== 0 ? this.age-s.age :num2 ;
		return num3 ;
	}	
}
/*TreeSet集合存储自定义对象(Student)
* 
* 	按照姓名的长度从小到大进行比较 :主要条件*/
public class TreeSetDemo {
	public static void main(String[] args) {
		
		//创建TreeSet集合,实现对该类型自然排序
		TreeSet<Student> ts = new TreeSet<Student> ();
		
		//创建学生对象
		Student s1 = new Student("gaoyuanyuan", 27) ;
		Student s2 = new Student("zhangguorong",29) ;
		Student s3 = new Student("wuqilong", 40) ;
		Student s4 = new Student("liushishi", 28) ; 
		Student s5 = new Student("fengqingy", 29) ;
		Student s6 = new Student("gaoyuanyuan", 22) ;
		Student s7 = new Student("gaoyuanyuan", 27) ;
		
		//添加元素
		ts.add(s1) ;
		ts.add(s2) ;
		ts.add(s3) ;
		ts.add(s4) ;
		ts.add(s5) ;
		ts.add(s6) ;
		ts.add(s7) ;

		//遍历
		for(Student s:ts) {
			System.out.println(s.getName()+"---"+s.getAge());
		}
	}
}    //wuqilong---40
    //fengqingy---29
    //liushishi---28
    //gaoyuanyuan---22
    //gaoyuanyuan---27
    //zhangguorong---29

我们可以看到,是按照姓名的长度排列的,当长度一样的时候,是按照年龄大小排的。

我们再来看比较器排序,它有两种方式。

  两种方式:
  1)自定义一个类,该类实现Comparator接口,重写Comparator接口中的compare()方法
2)直接使用接口匿名内部类的方式实现

(1)

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;
	}
}
//自定义类,该类实现Comparator保证集合中的元素进行比较器排序
public class MyComparator implements Comparator<Student> {

	@Override
	public int compare(Student s1, Student s2) {
		
		/**
		 * 自然排序:Comparable 里面compareTo(Student s)
		 *this---->s1
		 *s---s
		 */
		//return 0;
		//按照姓名长度进行比较
		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 ;
	}
}

public static void main(String[] args) {
		
		//创建TreeSet集合对象
                //TreeSet<Student> ts = new TreeSet<Student>() ;	  //无参构造形式,自然排序
		//选择器排序
		//Comparator是一个接口
                TreeSet<Student> ts = new TreeSet<Student>(new MyComparator()) ;
                //创建学生对象
		Student s1 = new Student("gaoyuanyuan", 27) ;
		Student s2 = new Student("zhangguorong",29) ;
		Student s3 = new Student("wuqilong", 40) ;
		Student s4 = new Student("liushishi", 28) ; 
		Student s5 = new Student("fengqingy", 29) ;
		Student s6 = new Student("gaoyuanyuan", 22) ;
		Student s7 = new Student("gaoyuanyuan", 27) ;
		
		
		ts.add(s1) ;
		ts.add(s2) ;
		ts.add(s3) ;
		ts.add(s4) ;
		ts.add(s5) ;
		ts.add(s6) ;
		ts.add(s7) ;

		//遍历
		for(Student s:ts) {
			System.out.println(s.getName()+"----"+s.getAge());
		}
	}
}//wuqilong----40
//fengqingy----29
//liushishi----28
//gaoyuanyuan----22
//gaoyuanyuan----27
//zhangguorong----29

(2)

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;
	}
}
public static void main(String[] args) {
		
		//创建TreeSet集合对象
//		TreeSet<Student> ts = new TreeSet<Student>() ;	  //无参构造形式,自然排序
		//选择器排序
		//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) {
				
				/**
				 * 自然排序:Comparable 里面compareTo(Student s)
				 * 
				 *this---->s1
				 *s---s
				 */
				//return 0;
				//按照姓名长度进行比较
				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("gaoyuanyuan", 27) ;
		Student s2 = new Student("zhangguorong",29) ;
		Student s3 = new Student("wuqilong", 40) ;
		Student s4 = new Student("liushishi", 28) ; 
		Student s5 = new Student("fengqingy", 29) ;
		Student s6 = new Student("gaoyuanyuan", 22) ;
		Student s7 = new Student("gaoyuanyuan", 27) ;
		
		
		ts.add(s1) ;
		ts.add(s2) ;
		ts.add(s3) ;
		ts.add(s4) ;
		ts.add(s5) ;
		ts.add(s6) ;
		ts.add(s7) ;

		//遍历
		for(Student s:ts) {
			System.out.println(s.getName()+"----"+s.getAge());
		}
	}
}
//wuqilong----40
//fengqingy----29
//liushishi----28
//gaoyuanyuan----22
//gaoyuanyuan----27
//zhangguorong----29





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值