(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/51287142冷血之心的博客)
集合框架 Set的特点:无序,不可以重复元素。
保证元素唯一性的原理:判断元素的hashCode值是否相同。
如果相同,还会继续判断元素的equals方法,是否为true。
(2)TreeSet:可以对Set集合中的元素进行排序。
底层数据结构是二叉树。
保证元素唯一性的依据:compareTo方法return 0。
一、HashSet相关知识
HashSet中的元素不可以重复,如果重复添加,则只会显示一个。
原理如下:
HashSet:底层数据结构是哈希表。是线程不安全的。不同步。
HashSet是如何保证元素唯一性的呢?
答:是通过元素的两个方法,hashCode和equals来完成。
如果元素的HashCode值相同,才会判断equals是否为true。如果元素的hashcode值不同,不会调用equals。
*******对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法**********
代码1:
package com.package2;此demo将String类型的字符串添加进去,并且没有重复,结果如下:
import java.util.*;
public class HashSet222
{
public static void main(String[] args)
{
HashSet hs = new HashSet();
hs.add("java01");
hs.add("java01");
hs.add("java02");
hs.add("java03");
hs.add("java03");
hs.add("java04");
Iterator it = hs.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
}
java04
java02
java03
java01
由此我们可以断定,String类已经实现了hashcode()方法和equals()方法。打开,帮助文档,确实(这不是废话么^_^)
但是,如果我们要将自定义的元素add进HashSet中,则必须定义其自己的hashcode()方法和equals()方法。如下所示:
代码2:
package com.package2;import java.util.*;public class HashSet3 {public static void main(String[] args) {HashSet hs = new HashSet();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 it = hs.iterator();while(it.hasNext()){Person p = (Person)it.next();System.out.println(p.getName()+"::"+p.getAge());}}}class Person{private String name;private int age;Person(String name,int age){this.name = name;this.age = age;}public int hashCode(){System.out.println(this.name+"....hashCode");return name.hashCode()+age*37; //保证此元素的返回值尽量不一致。}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;}public String getName(){return name;}public int getAge(){return age;}}输出结果如下:
a1....hashCode
a2....hashCode
a3....hashCode
a2....hashCode
a2...equals..a2
a4....hashCode
a1::11
a3::13
a2::12
a4::14
由此可以看出,将元素add时,会首先调用元素的hashcode()方法,当返回值重复时,会调用其equals方法。缺少任何一种方法都构不成一个HashSet集合。
二、TreeSet相关知识
TreeSet有俩种排序方式。
TreeSet排序的第一种方式:让元素自身具备比较性。步骤:将add进TreeSet中的元素实现Comparable接口,并且覆盖compareTo方法。这种顺序也是元素的自然顺序,或者叫做默认顺序。
TreeSet的第二种排序方式。当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性(即利用其另一种构造函数建立对象)。在集合初始化时,就有了比较方式。
步骤:利用某个指定类实现Comparator接口,并且覆盖compare()方法,则此类会成为一个具备比较方法的类。在建立TreeSet的时候,将此类对象传入其中。
则此时,添加进TreeSet中的元素可按照指定比较方法进行排序。
下边举例演示俩种排序方式。
排序方式一:代码1:
package com.package1;import java.util.*;public class TreeSettest {public static void main(String[] args) {//创建对象TreeSet ts=new TreeSet();//添加元素ts.add("abcjjj");ts.add("abb");ts.add("daccc");ts.add("gfg");ts.add("geee");ts.add("r");//进行迭代Iterator it=ts.iterator();//循环取出元素while(it.hasNext()){System.out.println(it.next());}}}输出结果如下:
abb
abcjjj
daccc
geee
gfg
r
由此可见,此时元素具备可比性,即按照其自然顺序进行排序。打开帮助文档,我们可以清晰的发现String已经实现了Comparable接口,并且已经覆盖了compareTo(),“这不是废话么^_^”,如图所示:
ps……如果我们要往TreeSet里添加的元素是自己刚刚定义的,我们也可以自己定义该元素的类实现Comparable接口,并且覆盖compareTo()方法,如下所示:代码2:
package com.package1;import java.util.*;class Student implements Comparable//该接口强制让学生具备比较性。{private String name;private int age;Student(String name,int age){this.name = name;this.age = age;}public int compareTo(Object obj){//return 0;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;/**/}public String getName(){return name;}public int getAge(){return age;}}public class TreeSet2 {public static void main(String[] args) {TreeSet ts = new TreeSet();ts.add(new Student("lisi02",22));ts.add(new Student("lisi02",21));ts.add(new Student("lisi007",20));ts.add(new Student("lisi09",19));ts.add(new Student("lisi06",18));ts.add(new Student("lisi06",18));ts.add(new Student("lisi007",29));//ts.add(new Student("lisi007",20));//ts.add(new Student("lisi01",40));Iterator it = ts.iterator();while(it.hasNext()){Student stu = (Student)it.next();System.out.println(stu.getName()+"..."+stu.getAge());}}}
结果如下:
lisi06...18
lisi09...19
lisi007...20
lisi02...21
lisi02...22
lisi007...29
此例子将学生元素,强行按照年龄来排序,这就是我们想要的排序方式。
第二种排序如下:
还是刚刚代码1的例子,我们使用第二种排序方式,使得String类型的元素按照长度来排序。
代码3:
/* * 使元素按照长度来排序,若长度相同,则按照自然排序。 */public class TreeSettest {public static void main(String[] args) {//创建对象TreeSet ts=new TreeSet(new MyCompare());//添加元素ts.add("abc");ts.add("bcc");ts.add("das");ts.add("bcde");ts.add("asdfg");ts.add("befqfca");//进行迭代Iterator it=ts.iterator();//循环取出元素while(it.hasNext()){System.out.println(it.next());}}}//定义一个类实现Comparator接口,并且覆盖compare()方法。class MyCompare implements Comparator{@Overridepublic int compare(Object o1, Object o2) {//进行强制类型转换String s1=(String) o1;String s2=(String) o2;//进行比较if(s1.length()>s2.length())return 1;if(s1.length()<s2.length())return -1;if(s1.length()==s2.length()){return s1.compareTo(s2);}return 0;}}结果如下:
abc
bcc
das
bcde
asdfg
befqfca
此种情况下,我们不方便修改源代码,而只需要修改比较方法时,我们就可以自己创建一个比较器。在建立TreeSet时,将比较器传入即可使元素按照特定比较方式输出。
总结:
Comparable(方式一)接口和Compartor(方式二)接口的比较:
两种方法各有优劣, 用Comparable 简单, 只要实现Comparable 接口的对象直接就成为一个可以比较的对象,但
是需要修改源代码。
用Comparator 的好处是不需要修改源代码, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把
比较器和对象一起传递过去就可以比大小了, 并且在Comparator 里面用户可以自己实现复杂的可以通用的逻辑,使其
可以匹配一些比较简单的对象,那样就可以节省很多重复劳动了。
如果对你有帮助,记得点赞哦~欢迎大家关注我的博客,可以进群366533258一起交流学习哦~