Set
-
- Set体系
- HashSet
- TreeSet-------
Set体系
Set : 元素是无序的(存入和取出的顺序不一定一致),元素不可以重复
Set集合的功能和Collection 是一致的
Set体系常用集合容器(HashSet / TreeSet)
- HashSet : 底层数据结构是哈希表
- TreeSet : 底层数据结构是二叉树,可以对Set集合中的元素进行排序
HashSet
HashSet 是如何保证元素的唯一性?
是通过两个方法: hashCode 和equals 来完成
每个元素都有自身的哈希值, 而HashSet底层是哈希表, 用来存放哈希值的
如果元素的HashCode值相同, 才会判断equals是否为true
如果元素的HashCode值不相同,则不会调用equals
.
1,hashCode获取元素哈希值
2,判断集合内是否有与之相同的哈希值,如果有,则调用equals判断元素是否相同,如果没有则存入集合中
!注:对于判断元素是否存在,以及删除等操作,依赖的方法也是元素的hashCode 和equals
一般的,hashCode 和equals 方法都要根据实际需求,实际判断条件来重写
代码演示------
本例中,如果按照默认hashCode 方法来new对象,则每个对象的哈希值都是不同的,但是对象的条件可能是相同的
所以根据条件可以自定义哈希值,
import java.util.*; //导入集合类包
//自定义人对象,对象添加到hashSet集合中,同名同年龄为重复元素
class Person {
private String name;
private int age;
public int hashCode() {
System.out.println(name + " hashCode " + name.hashCode());
return name.hashCode() + age * 29; //根据实际条件可以自定义哈希值,保证了哈希值的唯一性,减少调用equals
}
public boolean equals(Object obj) { //重写equals定义判断条件
if (!(obj instanceof Person)) { //判断输入元素是否为Person,否则返回false
return false;
}
Person p = (Person) obj; //多态.向下转型才能调用子类成员
System.out.println(this.name + " equals " + p.name); //参考,,哪段代码调用了equals
return this.name.equals(p.name) && this.age == p.age; //定义判断条件:名字,年龄相同就返回true
}
Person(String name, int age) {
this.age = age;
this.name = name;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public class DEMO {
public static void main(String[] args) {
HashSet hs = new HashSet();
hs.add(new Person("java1", 10));
hs.add(new Person("java2", 12));
hs.add(new Person("java1", 10));
hs.add(new Person("java3", 13));
hs.add(new Person("java3", 13));
System.out.println("------------------------");
sop("是否包含 " + hs.contains(new Person("java1", 10)));
System.out.println("------------------------");
Iterator it = hs.iterator(); //对集合进行迭代
while (it.hasNext()) {
Person p = (Person) it.next();
System.out.println(p.getName() + " " + p.getAge());
}
}
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2csoXSU1UNRpnT4FleYhnRzwEMW1mY1RzRapnTtxkb5ckYplTeMZTTINGMShUYfRHelRHLwEzX39GZhh2css2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xyayFWbyVGdhd3LcV2Zh1Wa9M3clN2byBXLzN3btg3Pn5GcuYDNzQTOyMjM2IjMxgTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
TreeSet-------
TreeSet :底层数据结构是二叉树, 可以对Set集合中的元素进行排序
保证唯一性的依据是:int compareTo return 0;
TreeSet排序的第一种方式----- Comparable
让元素自身具备比较性,元素需要实现Comparable接口,覆盖comparaTo方法,这种方式称为元素的自然排序
int compareTo(T o) -----比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
TreeSet排序的第二种方式----- Comparator(比较器)
当元素内部不具备比较性,或者元素具备的比较性不是所需要的
那这时可以可以定义一个 Comparator(比较器)类,在比较器内重写conpare方法定义比较条件
int compare(T o1,T o2) ------ 比较用来排序的两个参数。根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数。
注:java很多类中已经定义了Comparable,如 String类,Integer类
注:当元素中具备Comparable,又定义了Comparator…最终是调用Comparator来对元素进行排序
Comparable 与 Comparator(比较器) 区别
- Comparable可以认为是一个内比较器…Comparator可以认为是是一个外比较器
- 如果实现类没有实现Comparable接口,又想对两个类进行比较(或者实现类实现了Comparable接口,但是对compareTo方法内的比较算法不满意),那么可以实现Comparator接口,自定义一个比较器,写比较算法
Comparable 代码演示-----
将学生对象存入 TreeSet中
根据年龄为主要条件进行排序,姓名为次要条件
当主条件相同时,判断次要条件
import java.util.*; //导入集合类包
class Student implements Comparable{ //继承Comparable 让学生具备比较性
private String name;
private int age;
Student(String name, int age){
this.name=name;
this.age=age;
}
public int compareTo(Object obj){ //重写conpareTo方法,重新定义年龄为主要比较条件,姓名为次要条件
if (!(obj instanceof Student)){ //如果对象不是学生,则抛出异常
throw new RuntimeException("不是学生对象");
}
Student s=(Student)obj; //向下转型
System.out.println(this.name+" conpar "+s.name); //参考代码调用该方法
if (this.age>s.age)
return 1;
if (this.age==s.age){
return this.name.compareTo(s.name); //当年龄相同时,则判断次要条件:姓名,
} //因为String类中已经定义了比较comparable,所以可以直接调用conpareTo
return -1;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
}
public class DEMO {
public static void main(String[] args) {
TreeSet ts = new TreeSet();
ts.add(new Student("java1",10));
ts.add(new Student("java3",13));
ts.add(new Student("java2",13));
ts.add(new Student("java2",13));
System.out.println("--------------------");
Iterator it=ts.iterator();
while (it.hasNext()){
Student s=(Student)it.next();
System.out.println(s.getName()+" "+s.getAge());
}
}
}
Comparator 代码演示------
将学生对象存入 TreeSet中,定义一个比较器类,并使用该比较器
根据姓名为主要条件进行排序,年龄为次要条件
当主条件相同时,判断次要条件
import java.util.*; //导入集合类包
class Student{
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;
}
}
class MyCompare implements Comparator{ //定义比较器,实现Comparator接口
public int compare(Object o1,Object o2){ //重写conpare方法
Student s1=(Student)o1;
Student s2=(Student)o2;
int num= s1.getName().compareTo(s2.getName()); //比较姓名
if (num==0){
return new Integer(s1.getAge()).compareTo(s2.getAge()); //当姓名相同时,比较年龄
}
return num ;
}
}
public class DEMO {
public static void main(String[] args) {
TreeSet ts = new TreeSet(new MyCompare()); //调用比较器
ts.add(new Student("java3",16));
ts.add(new Student("java1",13));
ts.add(new Student("java2",10));
ts.add(new Student("java7",10));
ts.add(new Student("java7",9));
Iterator it=ts.iterator();
while (it.hasNext()){
Student s=(Student)it.next();
System.out.println(s.getName()+" "+s.getAge());
}
}
}
TreeSet练习-------
练习:按照字符串的长度排序,相同长度则按自然排序
字符串本身具备了比较性(Comparable),但是它的比较性不是我们所需的
这时则需要定义比较器(Comparator),
import java.util.*; //导入集合类包
class MyCompare implements Comparator{ //定义比较器,实现Comparator接口
public int compare(Object o1,Object o2) { //重写conpare方法
String s1=(String)o1;
String s2=(String)o2;
//int num =new Integer(s1.length()).compareTo(s2.length()); 这种写法更简便
if (s1.length()>s2.length()){
return 1;
}else if (s1.length()==s2.length()){
return s1.compareTo(s2); //长度相同则进行自然排序比较
}return -1;
}
}
public class DEMO {
public static void main(String[] args) {
TreeSet ts = new TreeSet(new MyCompare()); //调用比较器
ts.add("caaddd");
ts.add("z");
ts.add("abc");
ts.add("aaa");
ts.add("yacccdsad");
Iterator it=ts.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
}
}