内容
1.List
2.哈希表原理图
3.HashSet
4.SortedSet
在正式讲解之前,还是把上一篇的一个图拿过来。这个图十分重要
一.List
1.List介绍
(1)List是接口,继承Collection
(2)List集合存储元素的特点
①有序(List集合中存储有下标,类似于数组)
存进去是什么顺序,取出来还是按照这个顺序取出
②可重复
2.List使用
import java.util.*;
public class 测试程序 {
public static void main(String[] args) {
//1.创建List集合(List集合是接口,继承Collection)
List a = new ArrayList();//括号里填初始化容量,不填默认是10
//2.添加元素
a.add(1);
a.add(2);
a.add(3);
a.add(4);
a.add(4);
//遍历
Iterator b = a.iterator();
while(b.hasNext()) {
System.out.println(b.next());
}
}
}
3.深入List集合
①ArrayList集合和Vector集合底层是数组,数组是有下标的,所以它有很多类似数组的特性
②ArrayList集合底层默认初始化容量是 10 ,扩大之后的容量是原容量的1.5倍
③Vector集合底层默认初始化容量也是10,扩大之后的容量是原容量的2倍
④如何优化?
尽量减少扩容操作,因为扩容需要数组拷贝,数组拷贝很耗内存。一般推荐在创建集合的时候指定初始化容量
4.使用示例
import java.util.*;
public class 测试程序 {
//深入List
public static void main(String[] args) {
//1.创建List集合(List集合是抽象类,继承CollectionayList();
List a = new ArrayList();
//2.添加元素
a.add(1);
a.add(2);
a.add(3);
//2.在下标为1的位置上添加6
a.add(1,6);
//3.取得元素
System.out.println(a.get(0));//输出1
System.out.println(a.get(1));//输出6
//遍历(List集合特有的遍历方式)
for(int i = 0;i < a.size();i++) {
Object element = a.get(i);
System.out.println(element);
}
}
}
二.哈希表原理图
三.HashSet
1.特点及注意事项
1.HashSet底层实际上是一个HashMap,HashMap底层采用了哈希表数据结构(原理图在上面)
2.hashSet其实是HashMap中的key部分,HashSet有什么特点,HashMap中的key应该具有相同的特点
3.HashMap和HashSet初始化容量都是 16 ,默认加载因子是0.75
2.哈希表
①哈希表又叫做散列表,哈希表底层是一个数组,这个数组中每一个元素是一个单向链表。
②每个单向链表都有一个独一无二的hash值,代表数组的下标。在某个单向链表中的每一个节点上的hash值是相等的
③hash值实际上是key调用hashCode方法,再通过“hash function”转换成的值
3.如何向哈希表中添加元素
①先调用被储存的key的hashCode方法,经过某个算法得出hash值。
②如果在这个哈希表中不存在这个hash值,则直接加入元素,如果该hash值已经存在,继续调用key之间的equals方法。
③如果equals方法返回false,则将该元素添加,如果equals方法返回true,则放弃添加该元素
4.使用示例
import java.util.*;
public class 测试程序 {
public static void main(String[] args) {
//1.创建Set集合
Set s = new HashSet();
//2.添加元素,验证它是无序不可重复的
//Set集合通常不能记住元素的添加顺序
s.add(1);
s.add(1);//这个就加不上去了
s.add(100);
s.add(86);
s.add(110);
//遍历
Iterator it = s.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
}
注意:Set集合通常不能记住元素的添加顺序,并不是说一定不按顺序。但是它不允许有相同元素再添加这个是一定的。
5.关于往Set集合中存储的元素,该元素的hashCode和equals方法
注意
存储在HashSet集合或者HashMap集合key部分的元素,需要同时重写 hashCode和equals方法
使用示例
import java.util.*;
public class 测试程序 {
/*
* 关于往Set集合中存储的元素,该元素的hashCode和equals方法
* HashMap中有一个put方法,put(key,value) key是无序不可重复的
结论:
存储在HashSet集合或者HashMap集合key部分的元素,需要同时重写 hashCode和equals方法
*/
public static void main(String[] args) {
//1.创建Set集合
Set s = new HashSet();
//2.创建员工对象
Employee e1 = new Employee("1000","Jack");
Employee e2 = new Employee("1000","Jack");
Employee e3 = new Employee("2000","SCOTT");
Employee e4 = new Employee("2001","SMITCH");
Employee e5 = new Employee("3000","JIM");
Employee e6 = new Employee("3001","JOHN");
System.out.println(e1.hashCode());
System.out.println(e2.hashCode());
/*
* 输出
* 1507423
1507423
两者相同,同时也验证了String中hasCode()方法的特点:只要字符串一样,就返回相同的值
验证了结论
*/
//3.添加元素
s.add(e1);
s.add(e2);
s.add(e3);
s.add(e4);
s.add(e5);
s.add(e6);
//4.查看集合中元素的个数
System.out.println(s.size());
/*
* 在没有重写Employee中的hasCode和equals方法的时候,这里输出6
* 但是按照现实的业务逻辑,e1和e2是同一个人,e2不应该再加进去
* 但是因为e1和e2都是new出来的。它们经过hasCode方法之后得到的值是不一样的,所以就加进去了
* 所以这里为了避免这样的问题,应该重写hasCode和equals方法
*/
//重写了之后,就输出5
}
}
//创建员工类
class Employee{
String num;
String name;
Employee(String num,String name){
this.num = num;
this.name = name;
}
//重写hasCode方法
public int hashCode() {
//直接以员工编号分组
//String已经重写了hasCode方法,直接返回String的就可以
return num.hashCode();//如果两个编号相同,则返回相同的值
}
//重写equals方法
public boolean equals(Object o) {
if(this == o) return true;
if(o instanceof Employee) {
Employee temp = (Employee)o;
if(temp.num.equals(this.num) && temp.name.equals(this.name)) {
return true;
}
}
return false;
}
}
先去重写hashCode方法,再去重写equals方法,前者第一,后者第二。前者执行完,再执行后者
四.SortedSet
1.介绍
①SortedSet继承Set,也是一个接口,实现类是TreeSet
②SortedSet存储的数据无序不可重复,但是存进去的元素可以按照元素大小顺序自动排列
2.使用示例(验证特点)
package 对象;
import java.util.*;
import java.text.*;
public class 测试程序 {
public static void main(String[] args) throws ParseException {
//1.创建集合
SortedSet ss = new TreeSet();
//2.添加整型元素
ss.add(10);
ss.add(20);
ss.add(40);
ss.add(30);
ss.add(25);
ss.add(13);
//3.遍历,验证
Iterator it = ss.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
/*输出:
* 10
13
20
25
30
40
*/
//1.创建集合
SortedSet strs = new TreeSet();
//2.添加字符串数据
strs.add("JACK");
strs.add("SUN");
strs.add("KOOK");
strs.add("LUCY");
strs.add("KING");
//3.遍历,验证
it = strs.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
/*
* 输出
* JACK
KING
KOOK
LUCY
SUN
是从a~z开始比较,第一个字母相同就比第二个字母。
所以再一次得到验证,字符串也可以
*/
//1.创建集合
SortedSet times = new TreeSet();
//2.创建日期
String st1 = "2019-01-01";
String st2 = "2020-01-01";
String st3 = "2019-08-01";
String st4 = "2017-01-01";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date t1 = sdf.parse(st1);
Date t2 = sdf.parse(st2);
Date t3 = sdf.parse(st3);
Date t4 = sdf.parse(st4);
//3.添加元素
times.add(t1);
times.add(t2);
times.add(t3);
times.add(t4);
//3.遍历,验证
it = times.iterator();
while(it.hasNext()) {
Object element = it.next();
if(element instanceof Date) {
Date d = (Date)element;
System.out.println(sdf.format(d));
}
}
/*
* 输出:
* 2017-01-01
2019-01-01
2019-08-01
2020-01-01
*/
}
}
3.为何SortedSet集合存储元素可以自动排序?
因为被存储的元素实现了Comparable接口,SUN编写TreeSet集合在添加元素的时候,会调用compareTo方法完成比较,然后实现排序
4.示例:自己定义的类实现排序
package 对象;
import java.util.*;
public class 测试程序 {
public static void main(String[] args) {
//1.创建集合
SortedSet users = new TreeSet();
//2.创建对象
User u1 = new User(15);
User u2 = new User(16);
User u3 = new User(12);
User u4 = new User(11);
User u5 = new User(17);
//3.添加元素
users.add(u1);
users.add(u2);
users.add(u3);
users.add(u4);
users.add(u5);
//4.遍历
Iterator it = users.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
/*
* 输出
* User[age=11]
User[age=12]
User[age=15]
User[age=16]
User[age=17]
有升序也有倒序,主要是return那个地方age1和age2互换位置即可
*/
}
}
class User implements Comparable{//要想让自己单独定义的类可以比较,必须实现 Comparable接口
int age;
User(int age){
this.age = age;
}
//重写toString方法
public String toString(){
return "User[age="+age+"]";
}
//实现java.lang.Comparable接口中的comparaTo方法
//该方法程序员负责是实现,SUN提供的程序已经调用了该方法
public int compareTo(Object o) {
//编写一个比较规则
int age1 = this.age;
int age2 = ((User)o).age;
return age1 - age2;
}
}
5.SortedSet集合排序的另外一种方式
让SortedSet集合排序还有一个方式
即单独编写一个比较器。
具体做法是写一个类实现Comparator,因为Comparator是一个接口
6.使用示例
package 对象;
import java.util.*;
public class 测试程序 {
public static void main(String[] args) {
//1.创建集合
SortedSet products = new TreeSet(new ProductComparator());
//2.创建对象
Product p1 = new Product(1.0);
Product p2 = new Product(2.0);
Product p3 = new Product(1.1);
Product p4 = new Product(2.6);
//3.添加元素
products.add(p1);
products.add(p2);
products.add(p3);
products.add(p4);
//4.遍历
Iterator it = products.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
/*
* 输出
* 1.0
1.1
2.0
2.6
*/
}
}
//创建商品类
class Product{
double price;
Product(double price){
this.price = price;
}
//重写toString方法
public String toString() {
return price + "";
}
}
//单独编写一个比较器
class ProductComparator implements Comparator{
//需求:按照商品价格排序
public int compare(Object o1,Object o2) {
double price1 = ((Product)o1).price;
double price2 = ((Product)o2).price;
if(price1 == price2) {
return 0;
}else if(price1 > price2) {
return 1;
}else {
return -1;
}
}
}
推荐使用第二种方式,因为可以降低程序的耦合度。