黑马程序员——Java集合框架(2)

来源:互联网 发布:软件腰带剑开刃报价 编辑:程序博客网 时间:2024/06/05 13:49

Set的特点是元素无序,元素不可以重复,它有两个实现类:HashSet和TreeSet。

(1)HashSet:底层数据机构是哈希表,线程非同步

HashSet常用方法:

add(E e)添加元素成功则返回true,前提是之前未包含此元素,否则返回false。

contains(Object o)判断是否包含元素。

isEmpty()判断是否为空,是返回true,否则返回false

iterator()迭代器,用来遍历元素,是HashSet类唯一的获取元素的方法

size()返回元素数量

HashSet特性演示:

import java.util.*;public class hashset {public static void main(String[] args) {HashSet<String> hs=new HashSet<String>();hs.add("a");hs.add("b");hs.add("c");hs.add("d");System.out.println("add():"+hs.add("e"));System.out.println("hs集合:"+hs);System.out.println("contains():"+hs.contains("b"));System.out.println("isEmpty():"+hs.isEmpty());System.out.println("size():"+hs.size());Iterator hsit=hs.iterator();while(hsit.hasNext()){System.out.println(hsit.next());}}}

输出结果:

add():true
hs集合:[a, b, c, d, e]
contains():true
isEmpty():false
size():5
a
b
c
d
e

在这个输出结果中,集合中元素是按照被放入的顺序输出的,那HashSet是真正无序的吗?其实在元素不多且没有其他对象冲突的情况下,HashSet中的元素会根据其散列值排序。所以使用HashSet必须是顺序对应用没有影响时才选用。HashSet为了保证存储的元素不会重复,底层都会在每个元素进行存储时和之前的元素进行比较,至于什么样的两个元素算是重复的元素,就必须要说equals()和hashCode()两个方法。当往HashSet中增加元素的时候,HashSet的add方法会调用被添加对象的equals()和hashCode()两个方法,先调用hashCode()方法,看两个对象的哈希值是否相同,一旦相同,会继续调用equals()方法,判断两个对象的内容是否相同。一旦两个方法返回的都是相等,则HashSet判断两个对象是同一个对象。

这对于HashSet来说是非常重要的一点,当HashSet在存储自定义对象的时候需要在自定义类中复写equals()和hashCode()方法,说明在什么情况下,两个对象是相同的,不然HashSet可能会违背意愿的存入相同的对象。

 

没有复写equals()和hashCode()之前

import java.util.*;class Person{private String name;private String sex;public Person(String name,String sex){this.name=name;this.sex=sex;}public String toString(){return name+"..."+sex;}}public class hashset_hashcode {public static void main(String[] args) {HashSet<Person> hs=new HashSet<Person>();hs.add(new Person("张三","男"));hs.add(new Person("张三","男"));hs.add(new Person("张三","男"));hs.add(new Person("张三","男"));System.out.println(hs);}}

输出结果:

[张三...男, 张三...男, 张三...男, 张三...男]

很显然,“张三”,“男”被存储了4遍,对Person类来讲,一旦name和sex属性都相同,应该是同一个对象,不应该被存储4遍,这里出现问题的原因就是没有复写equals()和hashCode()方法。

复写equals()和hashCode()以后,看看结果是什么样的:

<span style="font-size:12px;">import java.util.*;class Person{private String name;private String sex;public Person(String name,String sex){this.name=name;this.sex=sex;}public int hashCode(){return name.hashCode()+10;}public boolean equals(Object o){if(!(o instanceof Person))return false;Person p=(Person)o;return this.name.equals(p.name) && this.sex == p.sex;}public String toString(){return name+"..."+sex;}}public class hashset_hashcode {public static void main(String[] args) {HashSet<Person> hs=new HashSet<Person>();hs.add(new Person("张三","男"));hs.add(new Person("张三1","男"));hs.add(new Person("张三2","男"));hs.add(new Person("张三","男"));System.out.println(hs);}}</span>

输出结果:

[张三...男, 张三1...男, 张三2...男]

从上面的结果可以看出,最后一个“张三”,“男”没有存进去。同理,在HashSet中,判断是否包含一个元素,和删除的元素在集合中是否存在,也会调用equals()和hashCode()方法。

 

(2)TreeSet:可以对Set集合中的元素进行排序

import java.util.*;public class treeset { public static void main(String[] args) {TreeSet<String> ts=new TreeSet<String>();ts.add("c");ts.add("b");ts.add("a");ts.add("d");System.out.println(ts);}}

输出结果:

[a, b, c, d]

可见无论添加元素的顺序怎样,TreeSet都将元素进行了排序。那么TreeSet是按照什么规则进行排序的呢?下面就来分析这个问题。

先定义一个自定义的Person类,之后再TreeSet中添加这个类,看看什么结果。

import java.util.*;class Student{private String name;private int age;public Student(String name,int age){this.name=name;this.age=age;}public String toString(){return name+"..."+age;}}public class treeset_compareto {public static void main(String[] args) {TreeSet<person> ts=new TreeSet<person>();ts.add(new Student("张三",18));ts.add(new Student("张三",16));ts.add(new Student("张三",20));ts.add(new Student("张三",26));System.out.println(ts);}}

输出结果:


Exception in thread "main" java.lang.ClassCastException: collection.person cannot be cast to java.lang.Comparable
 at java.util.TreeMap.compare(Unknown Source)
 at java.util.TreeMap.put(Unknown Source)
 at java.util.TreeSet.add(Unknown Source)
 at collection.treeset_compareto.main(treeset_compareto.java:20)

 

这里报出了ClassCastException异常,说是Student没有实现Comparable接口。来看看这个接口是干什么的?查API发现,此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。

看来要实现TreeSet的还要实现这个接口,并且重写这个compareTo方法才行,看看这个方法的要求:比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。 

按照要求重新写下Student类,现在看看打印结果

import java.util.*;class Student implements Comparable{private String name;private int age;public Student(String name,int age){this.name=name;this.age=age;}@Overridepublic int compareTo(Object o) {          if(!(o instanceof Student)){              throw new RuntimeException();          }          Student s = (Student) o;          if(this.age > s.age){              return 1;          }          if(this.age < s.age){              return -1;          }          return 0;      }        public String toString(){return name+"..."+age;}}public class treeset_compareto {public static void main(String[] args) {TreeSet<Student> ts=new TreeSet<Student>();ts.add(new Student("张三",18));ts.add(new Student("张三",16));ts.add(new Student("张三",20));ts.add(new Student("张三",26));System.out.println(ts);}}

输出结果:

[张三...16, 张三...18, 张三...20, 张三...26]

 

排序成功,TreeSet根据compareTo方法的定义,用年龄对Student类的对象进行了排序。




 


 

0 0
原创粉丝点击