(尊重劳动成果,转载请注明出处: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;
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());
}
}
}
此demo将String类型的字符串添加进去,并且没有重复,结果如下:
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
{
@Override
public 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一起交流学习哦~