集合的体系:
-----------------Collection 单例集合接口
----------------------List 如果实现的是List接口的集合,具备有序,可重复的特性
-----------------------------ArrayList 底层是维护了一个Object数组实现的。 特点: 查询速度快,增删慢。
-----------------------------LinkedList 底层是使用链表数据结构实现的,特点:查询速度慢,增删块
-----------------------------Vector 底层维护了一个Object类型的数组,和ArrayList 基本一致,特点:线程安全,但是操作效率低 (出现的早,西安基本被ArrayList 替代了)
----------------------Set 如果实现的是Set接口的集合,具备无序,不可重复的特性
-----------------------------HashSet 底层是使用了哈希表实现的,特点:存取快
-----------------------------TreeSet 底层是使用红黑树(二叉树)存储的,特点:直接排序(前提是元素具备自然顺序的属性)
-----------------------------------------本文重点对Set集合进行说明------------------------------------------------
HashSet:
存储的原理:
往HashSet中添加元素的时候,会先调用hashCode()方法,查询哈希值,然后通过得到的元素的哈希值然后通过移位等运算确定元素的存储位置;
1、当确定好的元素的位置处没有其他的元素,则直接将该元素存储在这个位置
2、当确定好的元素的位置处还有其他的元素,则会先调用元素的equals方法,确认两个元素是否一致,如果一致认为是重复元素,不会添加成功,如果不一致,继续添加到该位置处(hash存储是以桶的形式存储的,一个位置可以允许有多个元素)
如下是hashSet使用场景,一个简单的例子
/* 需求:支持从键盘输入用户名和密码,如果输入的用户名已经存在了 则不允许添加。。。 */ import java.util.HashSet; import java.util.Scanner; class User{ String username; String password; public User(String username,String password){ this.username = username; this.password = password; } @Override //重写equals方法,设置比较用户名 public boolean equals(Object obj) { User user = (User) obj; return this.username.equals(user.username); } @Override //重写toString方法,主要是用来显示已注册用户的(格式自定义) public String toString() { return "{"+username+":"+password+"}"; } @Override //重写hashCode方法,用用户名来确定存储位置 public int hashCode() { return this.username.hashCode(); } } public class hashSetPractise { static HashSet users = new HashSet(); static User user; public static void main(String[] args) { Scanner sc = new Scanner(System.in); while(true){ System.out.println("请输入用户名:"); String username= sc.next(); System.out.println("请输入密码:"); String password = sc.next(); user = new User(username,password); //add方法返回的是一个boolean类型的数据,true表示添加成功 if(users.add(user)){ System.out.println("注册成功"); System.out.println("当前注册的用户:"+users); }else{ System.out.println("重复注册了。。"); } } } }
TreeSet:
特点
如果元素具备自然顺序 的特性,那么就按照元素自然顺序的特性进行排序存储。
treeSet要注意的事项
1. 往TreeSet添加元素的时候,如果元素本身具备了自然顺序的特性,那么就按照元素自然顺序的特性进行排序存储(比如说元素是int类型数据,元素是char类型数据等)
2. 往TreeSet添加元素的时候,如果元素本身不具备自然顺序的特性(自定义的元素),那么该元素所属的类必须要实现Comparable接口,把元素的比较规则定义在compareTo(T o)方法上。
3. 如果比较元素的时候,compareTo方法返回 的是0,那么该元素就被视为重复元素,不允许添加.(注意:TreeSet与HashCode、equals方法是没有任何关系。)
4. 往TreeSet添加元素的时候, 如果元素本身没有具备自然顺序 的特性,而元素所属的类也没有实现Comparable接口,那么必须要在创建TreeSet的时候传入一个比较器(实际上就是单独定义一个类实现Comparator接口的的Compare方法)
5. 往TreeSet添加元素的时候,如果元素本身不具备自然顺序的特性,而元素所属的类已经实现了Comparable接口, 在创建TreeSet对象的时候也传入了比较器那么是以比较器的比较规则优先使用。
使用方法
1、具备自然顺序的就不在赘述,能实现自动排序,不需要比较器等其他方法;
2、实现Conparable接口的CompareTo方法实现
import java.util.TreeSet; /* 需求,定义一个员工类并传入员工,按照工资从小到大排序 */ class Emp implements Comparable{ int id; String name; int salary; public Emp(int id,String name,int salary){ this.id = id; this.name = name; this.salary = salary; } @Override public String toString() { return "{"+id+","+name+","+salary+"}"; } @Override //实现compareTo方法 //这个方法会返回一个负整数,零或正整数,代表该对象小于,等于或大于指定对象。 public int compareTo(Object o) { Emp emp = (Emp) o; return this.salary-emp.salary; } } public class treeSet { public static void main(String[] args) { TreeSet tree = new TreeSet(); tree.add(new Emp(110,"Mary",1800)); tree.add(new Emp(100,"kobe",1500)); tree.add(new Emp(109,"JackJones",3200)); tree.add(new Emp(440,"James",400)); //如果不实现Comparable的compareTo方法,会报错,因为默认treeSet会进行排序,不指定的话不知道依据什么排序 System.out.println(tree); } }
3、定义一个比较器(推荐使用比较器方法实现,会使代码更加灵活)
import java.util.Comparator; import java.util.TreeSet; class Emp { int id; String name; int salary; public Emp(int id,String name,int salary){ this.id = id; this.name = name; this.salary = salary; } @Override public String toString() { return "{"+id+","+name+","+salary+"}"; } } /* 定义一个比较器并实现compare方法,方法和compareTo一样,返回的是负整数,零或者正整数,分别代表小于,等于和大于 */ class MyCompare implements Comparator{ @Override public int compare(Object o1, Object o2) { Emp p1 = (Emp) o1; Emp p2 = (Emp) o2; return p1.id-p2.id; } } public class treeSet { public static void main(String[] args) { MyCompare myCompare = new MyCompare(); TreeSet tree = new TreeSet(myCompare); tree.add(new Emp(110,"Mary",1800)); tree.add(new Emp(100,"kobe",1500)); tree.add(new Emp(109,"JackJones",3200)); tree.add(new Emp(440,"James",400)); System.out.println(tree); } }