黑马程序员-集合类Collection之Set接口
2013-08-01 22:30
507 查看
-----------android培训、java培训、java学习型技术博客、期待与您交流!
------------
Set接口中的方法和Collection中方法一致的。Set接口取出方式只有一种,迭代器。
|--LinkedHashSet:有序,是hashset的子类。
|--TreeSet:底层的数据结构是二叉树。对Set集合中的元素进行指定顺序的排序,默认是自然顺序。不同步。
如果元素的HashCode值相同,才会继续调用equals方法来判断两元素是否相同:如果为true,那么视为相同元素,不存;如果为false,那么存储。
如果元素的HashCode值不同,不会调用equals,从而提高对象比较的速度。
注意:对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashCode和equals方法。往HashSet里面存的自定义元素一定要复写hashCode和equals方法,以保证元素的唯一性!
(2)哈希值就是这个元素的位置。要找元素时,先将该元素通过哈希算法算出哈希值,再通过哈希值到哈希表中去查找。
(3)如果哈希值出现冲突,再次判断这个关键字对应的对象是否相同。如果对象相同,就不存储,因为元素重复。如果对象不同,就存储,在原来对象的哈希值基础 +1顺延。
(4)存储哈希值的结构,我们称为哈希表。
(5)既然哈希表是根据哈希值存储的,为了提高效率,最好保证对象的关键字是唯一的。这样可以尽量少的判断关键字对应的对象是否相同,提高了哈希表的操作效率。
对于HashSet集合,判断元素是否存在,或者删除元素,底层依据的是hashCode方法和equals方法。
让元素自身具备比较性,需要添加的元素对象实现Comparable接口,覆盖compareTo方法。
如果元素不具备比较性,在运行时会发生ClassCastException异常。
所以需要元素实现Comparable接口,强制让元素具备比较性,复写compareTo方法。
依据compareTo方法的返回值,确定元素在TreeSet数据结构中的位置。
2)注意:
在进行比较时,如果判断条件不唯一,比如,同姓名,同年龄,才视为同一个人。
在判断时,需要分主要条件和次要条件,当主要条件相同时,再判断次要条件,按照次要条件排序。
3)代码示例:
自定义比较器的方法:定义一个类,实现Comparator接口,覆盖compare方法。
注意:第二种方式较为灵活。当两种排序都存在时,以比较器为主。
compara(Object a,Objectb)方法使用:
public int compare(Object a,Object b){
int i = b.对象属性- a.对象属性;
return i; //返回0,表示this==obj ;返回正数表示,this>obj; 返回负数,表示this<obj
}
------------
一、定义:
Set具有与Collection接口完全一样的接口,因此没有任何额外的功能;其实Set就是Collection,只是行为不同。二、特点:
无序的(存入和取出的顺序不一定一致),无索引,元素不可重复。Set接口中的方法和Collection中方法一致的。Set接口取出方式只有一种,迭代器。
三、子类:
|--HashSet:底层数据结构是哈希表,线程是不同步的。无序,高效;|--LinkedHashSet:有序,是hashset的子类。
|--TreeSet:底层的数据结构是二叉树。对Set集合中的元素进行指定顺序的排序,默认是自然顺序。不同步。
四、HashSet
1、保证性元素唯一的原理:
是通过元素的两个方法,hashCode和equals来完成。如果元素的HashCode值相同,才会继续调用equals方法来判断两元素是否相同:如果为true,那么视为相同元素,不存;如果为false,那么存储。
如果元素的HashCode值不同,不会调用equals,从而提高对象比较的速度。
注意:对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashCode和equals方法。往HashSet里面存的自定义元素一定要复写hashCode和equals方法,以保证元素的唯一性!
2、哈希表的原理:
(1)对对象元素中的关键字(对象中的特有数据),进行哈希算法的运算,并得出一个具体的算法值,这个值称为哈希值。(2)哈希值就是这个元素的位置。要找元素时,先将该元素通过哈希算法算出哈希值,再通过哈希值到哈希表中去查找。
(3)如果哈希值出现冲突,再次判断这个关键字对应的对象是否相同。如果对象相同,就不存储,因为元素重复。如果对象不同,就存储,在原来对象的哈希值基础 +1顺延。
(4)存储哈希值的结构,我们称为哈希表。
(5)既然哈希表是根据哈希值存储的,为了提高效率,最好保证对象的关键字是唯一的。这样可以尽量少的判断关键字对应的对象是否相同,提高了哈希表的操作效率。
3、对比:
对于ArrayList集合,判断元素是否存在,或者删元素,底层依据都是equals方法。对于HashSet集合,判断元素是否存在,或者删除元素,底层依据的是hashCode方法和equals方法。
4、代码示例:
/* 往hashSet集合中存入自定义对象 姓名和年龄相同为同一个人,重复元素。 */ import java.util.*; /* 往哈希表中的存储的自定义对象,必须覆盖hashCode方法,和equals方法。如果不知道这个对象到底存储到哪个容器中去, 那就将hashCode,equals,toString全都覆盖,创建对象自身的判断相同的依据。 */ class Person { // 声明属性 private String name; private int age; // 构造方法 Person(String name, int age) { this.name = name; this.age = age; } // getter,setter方法 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; } // 覆盖Object类中的hashCode方法。建立Person对象自己特有的哈希值算法。 public int hashCode() { System.out.println(this.name + "....hashCode"); final int NUMBER = 37; return name.hashCode() + age * NUMBER;// *37是为了尽量保证哈希值唯一。 } // 覆盖Object类中的equals方法,建立Person对象。判断是否相同的依据: 根据Person自身的特点来判断。 public boolean equals(Object obj) { if (!(obj instanceof Person)) return false; Person p = (Person) obj; System.out.println(this.name + "...equals.." + p.name); return this.name.equals(p.name) && this.age == p.age; } } class HashSetTest { public static void sop(Object obj) { System.out.println(obj); } public static void main(String[] args) { HashSet<Person> hs = new HashSet<Person>(); // 往哈希表中存储自定义对象。 hs.add(new Person("a1", 11)); hs.add(new Person("a2", 12)); hs.add(new Person("a3", 13)); hs.add(new Person("a2", 12)); hs.add(new Person("a4", 14)); Iterator<Person> it = hs.iterator(); while (it.hasNext()) { Person p = (Person) it.next(); sop(p.getName() + "::" + p.getAge()); } } } /*output: a1....hashCode a2....hashCode a3....hashCode a2....hashCode a2...equals..a2 a4....hashCode a1::11 a3::13 a2::12 a4::14 */
五、TreeSet:
1、特点:
底层数据结构式二叉树。可以用于对Set集合进行元素的指定顺序排序。排序需要依据元素自身具备的比较性。线程不同步。2、保证元素唯一性的方式:
参考Comparable接口的compareTo方法的返回值。也就是参考比较方法的结果是否为0,如果return 0,视为两个对象重复,不存。3、TreeSet集合排序有两种方式,Comparable和Comparator:
(1)自然排序(默认排序):
1)方法:让元素自身具备比较性,需要添加的元素对象实现Comparable接口,覆盖compareTo方法。
如果元素不具备比较性,在运行时会发生ClassCastException异常。
所以需要元素实现Comparable接口,强制让元素具备比较性,复写compareTo方法。
依据compareTo方法的返回值,确定元素在TreeSet数据结构中的位置。
2)注意:
在进行比较时,如果判断条件不唯一,比如,同姓名,同年龄,才视为同一个人。
在判断时,需要分主要条件和次要条件,当主要条件相同时,再判断次要条件,按照次要条件排序。
3)代码示例:
/* 需求: 往TreeSet集合中存储自定义对象学生。 想按照学生的年龄进行排序。 记住:排序时,当主要条件相同时,一定判断一下次要条件。 */ import java.util.*; class Student implements Comparable<Object> {// 该接口强制让学生具备比较性。 private String name; private int age; Student(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } public int compareTo(Object obj) { if (!(obj instanceof Student)) throw new RuntimeException("不是学生对象"); Student s = (Student) obj; System.out.println(this.name + "....compareto....." + s.name); if (this.age > s.age) return 1; if (this.age == s.age) { return this.name.compareTo(s.name); } return -1; } } class TreeSetTest1 { public static void main(String[] args) { TreeSet<Student> ts = new TreeSet<Student>(); ts.add(new Student("lisi02", 22)); ts.add(new Student("lisi007", 20)); ts.add(new Student("lisi09", 19)); ts.add(new Student("lisi08", 19)); ts.add(new Student("lisi007", 20)); ts.add(new Student("lisi01", 40)); Iterator<Student> it = ts.iterator(); while (it.hasNext()) { Student stu = (Student) it.next(); System.out.println(stu.getName() + "..." + stu.getAge()); } } } /*output: lisi007....compareto.....lisi02 lisi09....compareto.....lisi02 lisi09....compareto.....lisi007 lisi08....compareto.....lisi007 lisi08....compareto.....lisi09 lisi007....compareto.....lisi007 lisi01....compareto.....lisi007 lisi01....compareto.....lisi02 lisi08...19 lisi09...19 lisi007...20 lisi02...22 lisi01...40 */
(2)比较器:
1)使用条件及方法:
当元素自身不具备比较性(比如存储学生对象时)或者具备的比较性不是我们所需要的比较性时(比如想字符串的长度排序),此时就需要让集合自身具备自定义的比较性。那如何让集合自身具备比较性呢?可在集合初始化时,就让集合自身具备比较性,需要定义一个类(比较器),实现Comparator接口,并覆盖compare方法,将比较器对象作为实际参数传递给TreeSet集合的构造函数。自定义比较器的方法:定义一个类,实现Comparator接口,覆盖compare方法。
注意:第二种方式较为灵活。当两种排序都存在时,以比较器为主。
2)优先考虑比较器的原因:
实现implements Comparable接口定义排序有局限性,实现此接口只能按comparaTo()定义的这一种方法排序,如果同一对象有多种排序方式,应该定义不同的比较器,比如说学生对象可以按学号,分数,年龄等进行多种排序。3)自定义比较器实质:
让自己编写的类实现Comparator接口,重写Comparator中的比较方法compara(Object a,Objectb)compara(Object a,Objectb)方法使用:
public int compare(Object a,Object b){
int i = b.对象属性- a.对象属性;
return i; //返回0,表示this==obj ;返回正数表示,this>obj; 返回负数,表示this<obj
}
4)代码示例:
//让学生信息按照学生成绩排序输出 import java.util.Comparator; import java.util.Iterator; import java.util.Set; import java.util.TreeSet; /** * * 学术类 * */ class Student { /* 声明属性和方法 */ private String name; private Integer age; private Integer score; /* 构造方法 */ public Student(String name, Integer age, Integer score) { super(); this.name = name; this.age = age; this.score = score; } /* getter,setter方法 */ public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Integer getScore() { return score; } public void setScore(Integer score) { this.score = score; } @Override // 重写String,toString方法 public String toString() { return "姓名:" + name + " 年龄:" + age + " 成绩:" + score; } @Override // 重写hasCode()方法 public int hashCode() { return age * name.hashCode(); } @Override // 重写equals方法 public boolean equals(Object o) { Student s = (Student) o; return age == s.age && name.equals(s.name); } } /** * TreeSet测试类 */ /* 创建学生成绩比较器 */ class StudentScoreComparator implements Comparator<Student> { @Override public int compare(Student o1, Student o2) { int i = (int) (o2.getScore() - o1.getScore()); return i; } } public class TreeSetTest2 { public static void main(String[] args) { Set<Student> ts = new TreeSet<Student>(new StudentScoreComparator()); // 创建TreeSet集合 Student stu1 = new Student("张三", 18, 85); Student stu2 = new Student("李四", 19, 88); Student stu3 = new Student("李红", 20, 60); Student stu4 = new Student("张丽", 18, 90); ts.add(stu1); // 将对象放进TreeSet集合中 ts.add(stu2); ts.add(stu3); ts.add(stu4); Iterator<Student> it = ts.iterator(); // 声明迭代器 while (it.hasNext()) { System.out.println(it.next()); } } } /*output: 姓名:张丽 年龄:18 成绩:90 姓名:李四 年龄:19 成绩:88 姓名:张三 年龄:18 成绩:85 姓名:李红 年龄:20 成绩:60 */
5)练习:
/* 练习:按照字符串长度排序。 字符串本身具备比较性。但是它的比较方式不是所需要的。 这时就只能使用比较器。 */ import java.util.*; class StrLenComparator implements Comparator<Object> { public int compare(Object o1, Object o2) { String s1 = (String) o1; String s2 = (String) o2; int num = new Integer(s1.length()).compareTo(new Integer(s2.length())); if (num == 0) return s1.compareTo(s2); return num; } } class TreeSetTest { public static void main(String[] args) { TreeSet<String> ts = new TreeSet<String>(new StrLenComparator()); ts.add("abcd"); ts.add("cc"); ts.add("cba"); ts.add("aaa"); ts.add("z"); ts.add("hahaha"); Iterator<String> it = ts.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } } /*output: z cc aaa cba abcd hahaha */
相关文章推荐
- 黑马程序员-集合框架Collection List Set 接口的简单介绍
- 黑马程序员_Collection集合之Set
- 黑马程序员_java_集合框架_Collection_List_Set_泛型
- JAVA集合 Set(集)、List(列表)、Map(映射)、Collection(接口)
- collection集合接口子类---set接口
- 黑马程序员——集合框架collection集合接口及List子类
- 集合collection 下List接口和Set接口
- 黑马程序员----Set集合,Set派系的特点,Set接口方法,HashSet集合,对象的哈希值,TreeSet二叉树的排序效果
- Collection集合之六大接口(Collection、Set、List、Map、Iterator和Comparable)
- 黑马程序员-集合类Collection之List接口
- 黑马程序员_JAVA学习日记_JAVA中API:集合框架1(Collection,List,Set及其子类和迭代器的应用)
- 黑马程序员——Java基础---集合(一)---Collection、set、list
- 【java读书笔记】——Collection集合之六大接口(Collection、Set、List、Map、Iterator和Comparable)
- 【java读书笔记】——Collection集合之六大接口(Collection、Set、List、Map、Iterator和Comparable)
- 黑马程序员_学习笔记:9) 集合框架1:Collection(List、Set)、Iterator、List(ArrayList、LinkedList、Vector)
- 【java读书笔记】——Collection集合之六大接口(Collection、Set、List、Map、Iterator和Comparable)
- 黑马程序员-JAVA基础-Java 集合之Collection 接口和遍历方法
- 黑马程序员————java基础--------集合之set接口的特点及应用
- List,Set,Map是否继承自Collection接口? 答:List,Set是,Map不是。 Collection是最基本的集合接口,一个Collection代表一组Object,即Colle
- 黑马程序员_毕向东JAVA基础_集合(2)Collection&&List&&Set&&泛型