Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复,因为该集合体系没有索引。Set集合的功能Collection是一致的,取出只有一种方式 就是迭代器
----HashSet:底层数据结构是哈希表,线程是非同步的(有个子类可以实现有序,LinkedHashSet(链表结构和has结构相结合))
----TreeSet:可以对Set集合中的元素进行排序(自然排序,由小到大) 底层的数据结构是二叉树,线程不同步
HashSet集合:
1 import java.util.HashSet; 2 import java.util.Iterator; 3 4 public class HashSetDemo { 5 public static void main(String[] args) { 6 HashSet hs = new HashSet(); 7 /* 8 sop(hs.add("java01"));结果是true 9 sop(hs.add("java01"));结果是false,因为java01已经存在了就不在存了 10 */ 11 hs.add("java01"); 12 hs.add("java02"); 13 hs.add("java02");//返回结果为false,因为集合中已经有java02了 就不在存了 14 hs.add("java02"); 15 hs.add("java03"); 16 hs.add("java04"); 17 18 //set集合的取出只有一种方式 就是迭代器 19 for (Iterator it = hs.iterator(); it.hasNext();) { 20 System.out.println(it.next()); 21 } 22 } 23 }
HashSet是如何保证元素的唯一性的(判断元素相同的依据): 是通过元素的两个方法,hashCode和equals来完成
-如果元素的HashCode值相同,才会判断equals是否为true
-如果元素的hashcode值不同,不会调用equals
对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法
往hashSet集合中存入自定义对象.姓名和年龄相同为同一个人,重复元素。
1 import java.util.*; 2 public class HashSetTest{ 3 4 public static void main(String[] args) { 5 HashSet hs = new HashSet(); 6 7 hs.add(new Person("a1",11)); 8 hs.add(new Person("a2",12)); 9 hs.add(new Person("a3",13)); 10 hs.add(new Person("a2",12)); 11 hs.add(new Person("a4",14)); 12 13 Iterator it = hs.iterator(); 14 while (it.hasNext()){ 15 Person p = (Person)it.next(); 16 System.out.println(p.getName()+"::"+p.getAge()); 17 } 18 } 19 } 20 21 //以后开发中描述事物时,都要有复写hashCode和equals方法,因为可能这个对象会存储到HashSet集合中 22 class Person{ 23 private String name; 24 private int age; 25 26 public String getName() { 27 return name; 28 } 29 public void setName(String name) { 30 this.name = name; 31 } 32 public int getAge() { 33 return age; 34 } 35 public void setAge(int age) { 36 this.age = age; 37 } 38 39 public Person(String name, int age) { 40 super(); 41 this.name = name; 42 this.age = age; 43 } 44 45 //用于计算哈希值是否相等, 46 public int hashCode(){ 47 //return 60;//很多重复比较,导致哈希值都相同,要调用equals方法比较是不是同一个对象 48 return name.hashCode()+age*27;//*27是为了保证哈希值的唯一性,可以任何值都可以.每个字符串都有自己的哈希值 49 } 50 //用于比较两个对象是否相等 51 public boolean equals(Object obj){ 52 if (!(obj instanceof Person)) 53 return false; 54 55 Person p = (Person)obj; 56 return this.name.equals(p.name) && this.age == p.age; 57 } 58 }
记住:如果元素要存储到HashSet集合中,必须覆盖hashCode方法和equals方法。
一般情况下,如果定义的类会产生很多对象,比如人,学生,书,通常都需要覆盖equals,hashCode方法。建立对象判断是否相同的依据。
LinkedHashSet(链表结构和has结构相结合)):变集合中的元素变得有序(这里说的有序不是指排序而是指怎么存的顺序跟取出来的顺序是一样的)
1 import java.util.HashSet; 2 import java.util.Iterator; 3 import java.util.LinkedHashSet; 4 5 public class LinkedHashSetDemo { 6 public static void main(String[] args) { 7 8 HashSet hs = new LinkedHashSet(); 9 10 hs.add("hahah"); 11 hs.add("hehe"); 12 hs.add("heihei"); 13 hs.add("xixii"); 14 hs.add("hehe"); 15 16 Iterator it = hs.iterator(); 17 18 while(it.hasNext()){ 19 System.out.println(it.next()); 20 } 21 } 22 }
TteeSet:
1 import java.util.Iterator; 2 import java.util.TreeSet; 3 4 public class TreeSetDemo { 5 public static void main(String[] args) { 6 TreeSet ts = new TreeSet(); 7 8 ts.add("cab");//打印结果是对照字符编码表中对于的数值的大小排序 9 ts.add("aab"); 10 ts.add("dab"); 11 ts.add("Bab"); 12 13 Iterator it = ts.iterator(); 14 while (it.hasNext()){ 15 System.out.println(it.next()); 16 } 17 } 18 }
判断元素唯一性的方式:就是根据比较方法的返回结果是否是0,是0,就是相同元素,不存。
TreeSet对元素进行排序的方式一:让元素自身具备比较功能,元就需要实现Comparable接口。覆盖compareTo方法。
需求:往TreeSet集合中存储自定义对象。安照人的年龄进行排序
1 import java.util.Iterator; 2 import java.util.TreeSet; 3 4 public class TreeSetTest { 5 public static void main(String[] args) { 6 TreeSet ts = new TreeSet();//往TreeSet集合中的对象会自动排序的,所以往里存的对象必须要具有比较性 7 8 ts.add(new Person("jianqing",18)); 9 ts.add(new Person("jianfeng",14)); 10 ts.add(new Person("jianhuo",15)); 11 ts.add(new Person("jianguang",17)); 12 13 Iterator it = ts.iterator(); 14 while (it.hasNext()){ 15 Person p = (Person)it.next(); 16 System.out.println(p.getName()+"...."+p.getAge()); 17 } 18 } 19 } 20 //该接口强制让学生具备比较性 21 class Person implements Comparable{ 22 private String name; 23 private int age; 24 Person(String name,int age){ 25 this.name = name; 26 this.age = age; 27 } 28 29 public String getName(){ 30 return name; 31 } 32 public int getAge(){ 33 return age; 34 } 35 36 //实现了Compareble要覆盖该方法,这个方法在底层会自动调用,该方法可以给自定义对象进行排序 37 public int compareTo(Object obj){ 38 if (!(obj instanceof Person)) 39 throw new RuntimeException("不是人"); 40 Person p = (Person)obj; 41 if(this.age>p.age) 42 return 1; 43 if(this.age == p.age){ 44 return this.name.compareTo(p.name);//排序时,当主要条件相同时,一定要判断下次要条件。如果这里返回0 说明两个对象是同一个对象 45 } 46 return -1; 47 } 48 49 public boolean equals(Object obj){ 50 if (!(obj instanceof Person)) 51 return false; 52 53 Person p = (Person)obj; 54 return this.name.equals(p.name) && this.age == p.age; 55 } 56 }
当元素自身不具备比较性,或者具备的比较性不是所需要的(不能去改Person类的代码,有可能不是自己写的),这时需要让容器自身具备比较性
可以使用TreeSet集合第二种排序方式二:让集合自身具备比较功能,定义一个类实现Comparator接口,覆盖compare方法。将该类对象作为参数传递给TreeSet集合的构造函数。
当两种排序都存在时,以比较器为主(定义一个类,实现comparator接口,覆盖compare方法
1 import java.util.Comparator; 2 import java.util.Iterator; 3 import java.util.TreeSet; 4 5 public class TreeSetTest{ 6 public static void main(String[] args) { 7 TreeSet ts = new TreeSet(new MyCompare());//将比较器对象作为参数传递给TreeSet集合的构造函数。 8 9 ts.add(new Person("jianqing",18)); 10 ts.add(new Person("jianfeng",14)); 11 ts.add(new Person("jianhuo",15)); 12 ts.add(new Person("jianguang",17)); 13 14 Iterator it = ts.iterator(); 15 while (it.hasNext()){ 16 Person p = (Person)it.next(); 17 System.out.println(p.getName()+"...."+p.getAge()); 18 } 19 } 20 21 } 22 class Person implements Comparable{//该接口强制让学生具备比较性 23 private String name; 24 private int age; 25 Person(String name,int age){ 26 this.name = name; 27 this.age = age; 28 } 29 30 public int compareTo(Object obj){//实现了Compareble后这个方法在底层会自动调用 31 if (!(obj instanceof Person)) 32 throw new RuntimeException("不是人"); 33 Person p = (Person)obj; 34 if(this.age>p.age) 35 return 1; 36 if(this.age == p.age){ 37 return this.name.compareTo(p.name); 38 } 39 return -1; 40 } 41 42 public String getName(){ 43 return name; 44 } 45 public int getAge(){ 46 return age; 47 } 48 49 50 public boolean equals(Object obj){ 51 if (!(obj instanceof Person)) 52 return false; 53 54 Person p = (Person)obj; 55 return this.name.equals(p.name) && this.age == p.age; 56 } 57 } 58 //定义一个比较器,按照姓名排序 59 class MyCompare implements Comparator{ 60 public int compare(Object o1,Object o2){ 61 Person s1 = (Person)o1; 62 Person s2 = (Person)o2; 63 int num = s1.getName().compareTo(s2.getName()); 64 65 if(num==0){ 66 return (new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()))); 67 /* 68 if(s1.getAge()>s2.getAge()) 69 return 1; 70 if(s1.getAge()==s2.getAge()) 71 return 0; 72 return -1; 73 */ 74 } 75 return num; 76 } 77 }
怎么让TreeSet变成有序的:在比较中全部返回1,return 1;
二叉树原理图:
按照字符串长度排序。字符串本身具备比较性,但是他的比较方式不是所需要的。这时就只能使用比较器
1 import java.util.Comparator; 2 import java.util.Iterator; 3 import java.util.TreeSet; 4 5 class TreeSetTest{ 6 public static void main(String[] args) { 7 TreeSet ts = new TreeSet(new StrLenComparator()); 8 9 ts.add("huangjianfeng"); 10 ts.add("huangjianfei"); 11 ts.add("huangjianfeng.java"); 12 ts.add("huangjian"); 13 ts.add("jianfeng"); 14 15 for (Iterator it = ts.iterator();it.hasNext() ; ){ 16 System.out.println(it.next()); 17 } 18 } 19 } 20 21 class StrLenComparator implements Comparator{ 22 public int compare(Object o1,Object o2){ 23 String s1 = (String)o1; 24 String s2 = (String)o2; 25 /* 26 if(s1.length()>s2.length()) 27 return 1; 28 if(s1.length()==s2.length()) 29 return 0; 30 return -1; 31 */ 32 33 int num = new Integer(s1.length()).compareTo(new Integer(s2.length())); 34 if(num==0)//主要条件如果相同,要判断次要条件(如果String长度相同,要判断是否是相同的String) 35 return s1.compareTo(s2); 36 37 return num; 38 } 39 }