说明:Set集合中TreeSet和HashSet集合的存储原理是重点。
一,集合体系中常见实现类。
List接口常见实现类:
List集合中元素是有序的(即元素存入和去除的顺序是一致的),集合中元素可以重复,该集合体系有索引。
List集合判断元素是否相同,依据元素的equals方法。
实现类一:
ArrayList:
底层的数据结构使用的是数组结构。特点:查询元素块,但是增删稍慢,线程不同步,集合长度可变(默认=初始长度为10)超过容量时集合以50%自动增长;
实现类二:
LinkedList:
底层的数据结构使用的是链表结构。特点:增删速度很快,查询稍慢;
实现类三:
Vector:
底层数据结构为数组结构。特点:线程同步,效率较低,被ArrayLIst替代;
Set接口常见实现类;
Set集合中元素是无序的,元素不能重复。
实现类一:
HashSet:
底层数据结构是哈希表。
HashSet集合实现元素唯一性的方式:当向集合中存入元素时,判断该元素hashcode()方法的值与集合中原有元素的hashcode()值进行比较,如果不同,则认为集合中没有该元素,并向集合中存入该元素。当该元素与集合中原有元素的hashcode()值有相同时,系统会继续调用该元素的equals()方法,如果结构仍为true()则认为集合中已经存在该元素,不再存入。如果equals()结果为false(),则认为是不同的元素,并向集合中添加该元素。
注意:元素进入HashSet集合(即元素地址的哈希值进入HashSet集合),集合根据元素的哈希值排列元素顺序,与元素进入集合的顺序不一定相同。
由于Object类中的equals()方法是根据对象地址来判断结果的,所以在存入集合的元素对象一般会复写 hashcode()方法和equals()方法。
HashSet集合总判断元素是否存在,以及删除等操作都依赖于元素的hashcode()方法和equals()方法。
实现类二;
TreeSet:
底层数据结构式二叉树。
TreeSet集合可以对集合中的元素排序,默认排序方式为自然排序。
TreeSet集合保证集合元素唯一性的依据:当元素的compareTo()方法结果为0时,认为两元素相同。
TreeSet集合排序有两种方式:
第一种方式:让元素自身具备比较性,元素需要实现Comparable接口,覆盖接口的compareTo()方法,这种方式称为元素的自然顺序排序。
第二种方式:当元素本身不具备比较性,或者具备的比较性不是集合所需要的,在初始化集合时,会为集合定义比较器:先自定义一个比较器,将比较器对象做为参数传递黑TreeSet集合的构造函数。
二,HashSet集合示例
例1.当向HashSet集合中添加相同元素时,集合不会存入重复元素;
import java.util.*;
public class Test {
public static void main(String[] args){
//创建集合
HashSet hs=new HashSet();
//为集合添加元素
hs.add("aaa");
hs.add("bbb");
hs.add("ccc");
//当添加元素失败是,add()方法返回false.
System.out.println(hs.add("aaa"));
System.out.println(hs.add("bbb"));
//打印集合
System.out.println(hs);
}
}
运行结果:
false
false
[aaa, ccc, bbb]
从运行结果可以看出,当为HashSet集合添加已有元素时,添加失败,此时系统自动调用了字符串的hashcode()方法来判断字符串是否相同。
例2:向HashSet集合中添加自定义Student类对象,当Student对象姓名和年龄都相同时默认为同一个对象。
import java.util.*;
public class Test {
public static void main(String[] args){
//创建集合
HashSet hs=new HashSet();
//为集合添加元素
hs.add(new Student("aaa",11));
hs.add(new Student("bbb",22));
hs.add(new Student("ccc",33));
hs.add(new Student("aaa",44));
hs.add(new Student("ddd",33));
hs.add(new Student("aaa",11));//姓名和年龄与已有元素都相同
//打印集合
System.out.println(hs);
}
}
class Student{
private String name;
private int age;
Student(String name,int age){
this.name=name;
this.age=age;
}
//复写hashcode()方法
public int hashcode(){
return this.name.hashCode()+this.age*31;
}
//复写equals()方法
public boolean equals(Object obj){
if(!(obj instanceof Student))
return false;
Student stu=(Student)obj;
//当两对象姓名年龄都相同时返回true
return this.name.equals(stu.name)&&this.age==stu.age;
}
//复写toString()方法
public String toString(){
return this.name+"--"+this.age;
}
}
运行结果:
[aaa--44, ccc--33, aaa--11, aaa--11, bbb--22, ddd--33]
通过结果可以看到,只有姓名和年龄都相同时,才被认为是同一元素,
三,TreeSet集合示例
例1:在TreeSet集合中添加字符串,看集合是否为字符串自动排序
import java.util.*;
public class Test {
public static void main(String[] args){
//创建集合
TreeSet ts=new TreeSet();
//为集合添加元素
ts.add("xx");
ts.add("aa");
ts.add("yy");
ts.add("kk");
ts.add("cc");
ts.add("bb");
//打印集合
System.out.println(ts);
}
}
运行结果:
[aa, bb, cc, kk, xx, yy]
从结果可以看出,集合为元素进行了自然排序。
例2:向集合中添加自定义 Student类对象,并按照对象的年龄属性排序,当年龄相同时,按姓名的自然顺序排序。
import java.util.*;
public class Test {
public static void main(String[] args){
//创建集合
TreeSet ts=new TreeSet();
//为集合添加元素
ts.add(new Student("aaa",66));
ts.add(new Student("xxx",22));
ts.add(new Student("kkk",55));
ts.add(new Student("ddd",44));
ts.add(new Student("ddd",33));
ts.add(new Student("aaa",11));//
//打印集合
System.out.println(ts);
}
}
class Student implements Comparable{ //实现Comparable接口
private String name;
private int age;
Student(String name,int age){
this.name=name;
this.age=age;
}
//复写hashcode()方法
public int hashcode(){
return this.name.hashCode()+this.age*31;
}
//复写equals()方法
public boolean equals(Object obj){
if(!(obj instanceof Student))
return false;
Student stu=(Student)obj;
//当两对象姓名年龄都相同时返回true
return this.name.equals(stu.name)&&this.age==stu.age;
}
//复写compareTo()方法
public int compareTo(Object obj){
if(!(obj instanceof Student))
throw new RuntimeException("不是Student对象");
Student stu=(Student)obj;
int num=this.age-stu.age;
if(num==0)
return this.name.compareTo(stu.name);
return num;
}
//复写toString()方法
public String toString(){
return this.name+"-"+this.age;
}
}
运行结果:
[aaa-11, xxx-22, ddd-33, ddd-44, kkk-55, aaa-66]
通过结果可以看到,集合实现了我们自定义的排序方式,将元素按照年龄大小进行排序。
例3:向集合中添加自定义 Student类对象,且不按照Student类自定义的比较方式排序,而是通过传递比较器的方式按照姓名进行排序。当姓名相同时按照年龄的自然顺序排序。
import java.util.*;
public class Test {
public static void main(String[] args){
//创建集合,并传递自定义的比较器
TreeSet ts=new TreeSet(new MyCom());
//为集合添加元素
ts.add(new Student("aaa",66));
ts.add(new Student("xxx",22));
ts.add(new Student("kkk",55));
ts.add(new Student("ddd",44));
ts.add(new Student("ddd",33));
ts.add(new Student("aaa",11));//
//打印集合
System.out.println(ts);
}
}
//自定义一个按照学生姓名排序的比较器
class MyCom implements Comparator<Student>{
public int compare(Student s1,Student s2){
int num=s1.getName().compareTo(s2.getName());
if(num==0)
return s1.getAge()-s2.getAge();
return num;
}
}
//自定义类并实现Comparable接口,使该类对象具备比较性
class Student implements Comparable{
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;
}
//复写hashcode()方法
public int hashcode(){
return this.name.hashCode()+this.age*31;
}
//复写equals()方法
public boolean equals(Object obj){
if(!(obj instanceof Student))
return false;
Student stu=(Student)obj;
//当两对象姓名年龄都相同时返回true
return this.name.equals(stu.name)&&this.age==stu.age;
}
//复写compareTo()方法
public int compareTo(Object obj){
if(!(obj instanceof Student))
throw new RuntimeException("不是Student对象");
Student stu=(Student)obj;
int num=this.age-stu.age;
if(num==0)
return this.name.compareTo(stu.name);
return num;
}
//复写toString()方法
public String toString(){
return this.name+"-"+this.age;
}
}
运行结果:
[aaa-11, aaa-66, ddd-33, ddd-44, kkk-55, xxx-22]
通过结果看出,当为集合传递了比较器后,集合中的元素不再按照元素本身的比较性进行排序,而是按照比较器的方式来进行排序的,所以比较器的优先级要大于元素本身比较性的优先级。