目录
一、List 接口

  1. 概述
  2. List 接口中的抽象方法(特有)
  3. List 遍历
    二、ListIterator 接口
    1.概述
  4. ListIterator 接口的抽象方法
  5. List 逆向遍历:
    三、迭代器的并发修改异常
  6. 迭代器的并发修改异常
  7. 出现场景:
  8. 原因:
    四、ArrayList 、LinkedList 集合
  9. ArrayList 集合
  10. LinkedList 集合
  11. Vector 集合(基本不用)
    五、Set 接口
    六、 HashSet (哈希表)
  12. 特点
  13. 哈希表的数据结构
  14. 字符串对象的哈希值
  15. 哈希表的存储过程
  16. 哈希表的存储自定义对象
  17. LinkedHashSet 集合
  18. ArrayList,HashSet 判断对象是否重复的原因
    七、TreeSet
    1.概述
  19. TreeSet如何实现,不能存储重复元素
  20. 向TreeSet中放入,自定义的类的对象
  21. 注意事项

一、List 接口

  1. 概述
    继承 Collection 接口,它是一个元素存取 有序 的集合
    例如,存元素的顺序是11、22、33。那么集合中,元素的存储就是按照11、22、33的顺序完成的)

它是一个 带有索引 的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)

与 set 不同,List 中 可以有重复的元素,通过元素的 equals 方法,来比较是否为重复的元素

List 接口的常用实现类有:

ArrayList 集合

LinkedList 集合

  1. List 接口中的抽象方法(特有)
    add(int index, Object e) : 向集合指定索引处,添加指定的元素,原元素依次 后移
    remove(int index):将指定索引处的元素,从集合中删除,返回值为被删除的元素
    set(int index,E element):将指定索引处的元素,替换成指定的元素,返回值为替换前的元素
    get(int index):获取指定索引处的元素,并返回该元素
  2. List 遍历

List a = new LinkedList<>();
a.add(new Person(“zs”,10));
a.add(new Person(“lisi”,20));
a.add(new Person(“wangwu”,30));

//利用Iterator来遍历List
Iterator iterator = a.iterator();

//利用迭代器对象遍历
while(listItr.hasNext()) {
System.out.println(listItr.next());
}

//List独有的遍历方式
for (int i = 0; i < a.size(); i++) {
System.out.println(a.get(i));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
二、ListIterator 接口
1.概述
List 不仅有自己独有的迭代方式,还有自己独有的迭代器: ListIterator
2. ListIterator 接口的抽象方法
add(E, e):将指定元素插入列表
boolean hasPrevious():逆向遍历列表,若列表迭代器有多个元素,则返回 true,也就是判断是否有前一个元素
previous() :返回列表的前一个元素
3. List 逆向遍历:
Iterator iterator = a.iterator();
ListIterator listItr = a.listIterator(a.size());
//先顺序遍历,让 cursor 到最后
while(listItr.hasNext()) {
System.out.println(listItr.next());
}
//逆向遍历
//先previous向前移动一个位置,再访问cursor指向的元素
while(listItr.hasPrevious()) {
System.out.println(listItr.previous());
}
1
2
3
4
5
6
7
8
9
10
11
三、迭代器的并发修改异常

  1. 迭代器的并发修改异常
    java.util.ConcurrentModificationException

就是在遍历的过程中,使用了集合方法 修改了 集合的长度
2. 出现场景:
首先,在遍历集合的过程中修改集合;其次,修改集合行为,不是迭代器对象来完成的,而是直接修改 Collection 对象

//场景实现
List list = new ArrayList();
list.add(“abc1”);
list.add(“abc2”);
list.add(“abc3”);
list.add(“abc4”);

//对集合使用迭代器进行获取,获取时候判断集合中是否存在 “abc3"对象
//如果有,添加一个元素 “ABC3”
Iterator it = list.iterator();
while(it.hasNext()){
String s = it.next();
//对获取出的元素s,进行判断,是不是有"abc3”
if(s.equals(“abc3”)){
list.add(“ABC3”);
}
System.out.println(s);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
3. 原因:
在迭代过程中,使用了集合的方法对元素进行操作。导致迭代器并不知道集合中的变化,容易引发数据的不确定性。迭代器对象,是依赖与当前的数据集合产生的(换言之,迭代器依赖于数据集,它们必须对应)

public class ListDemo{
public static void main(String[] args) {
List a = new LinkedList<>();
//迭代器
ListIterator listItr = a.listIterator();

    a.add(new Person("zs",10));a.add(new Person("lisi",20));a.add(new Person("wangwu",30));while(listItr.hasNext()){Person p = listItr.next();//这种添加元素的方式,会产生异常//a.add(new Person("zhaoliu", 40));//解决: 利用ListIterator对象添加元素listItr.add(new Person("zhaoliu", 40));}
}
System.out.println(s);//针对List还有另外一种,在遍历集合同时修改集合的解决方案
for (int i = 0; i < a.size(); i++){if("lisi".equals(a.get(i).name)){a.add(new Person("zhaoliu", 40));}
}
System.out.println(a);
//如果使用 ListIterator 的add方法向集合中添加元素,这个元素的位置处在当前遍历到的元素之后的位置
//如果使用 集合对象的 add(e) 方法添加元素,插入的元素处在表尾位置

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
四、ArrayList 、LinkedList 集合

  1. ArrayList 集合
    底层采用的是 数组 结构,线程不安全,查询快,增删慢
    //创建了一个长度为0的Object类型数组
    ArrayList al=new ArrayList();
    al.add(“abc”);
    //本质:
    //底层会创建一个长度为10的Object数组 Object[] obj=new Object[10]
    //obj[0]=“abc”
    //如果添加的元素的超过10个,底层会开辟一个1.5*10的长度的新数组
    //把原数组中的元素拷贝到新数组,再把最后一个元素添加到新数组中
    1
    2
    3
    4
    5
    6
    7
    8

  2. LinkedList 集合
    底层采用 链表 结构,线程不安全,查询慢,增删快
    每次查询都要从链头或链尾找起,查询相对数组较慢,但是删除直接修改元素记录的地址值即可,不要大量移动元素
    LinkedList 的索引决定是从链头开始找还是从链尾开始找,如果该元素小于元素长度一半,从链头开始找起,如果大于元素长度的一半,则从链尾找起
    LinkedList 提供了大量的操作开始和结尾的方法
    子类的特有功能:不能多态调用:
    addFirst(E) 添加到链表的开头
    addLast(E) 添加到链表的结尾
    E getFirst() 获取链表的开头
    E getLast() 获取链表的结尾
    E removeFirst() 移除并返回链表的开头
    E removeLast() 移除并返回链表的结尾

  3. Vector 集合(基本不用)
    Vector 集合数据存储的结构是 数组 结构,为JDK中最早提供的集合,它是线程同步的,线程安全的
    Vector 集合已被 ArrayList 替代
    五、Set 接口

  4. 特点
    它是个 不包含重复元素 的集合,没索引

是一个不包含重复元素的 collection

无序集合,没有索引,不存储重复元素

Set无序:存储和取出的顺序不同,

Set集合取出元素的方式可以采用:迭代器、增强for

代码的编写上,和 ArrayList 完全一致

Set集合常用实现类:

HashSet 集合

LinkedHashSet 集合

六、 HashSet (哈希表)

  1. 特点:
    底层数据结构为 哈希表
    存储、取出都比较快
    线程不安全,运行速度快
    不保证 set 的迭代顺序
    不保证该顺序的恒久不变
  2. 哈希表的数据结构:
    加载因子:表中填入的记录数/哈希表的长度
    例如:加载因子是 0.75 代表:数组中的16个位置, 其中存入 16 * 0.75 = 12个元素。
    如果在存入第十三个( > 12 )元素,导致存储链子过长,会降低哈希表的性能,那么此时会扩充哈希表(再哈希),底层会开辟一个长度为原长度2倍的数组,把老元素拷贝到新数组中,再把新元素添加数组中。
    当 存入元素数量 > 哈希表长度 * 加载因子,就要扩容,因此加载因子决定扩容时机
  3. 字符串对象的哈希值:
    对象的哈希值,是普通的十进制整数,Object 类的方法 public int hashCode() 来计算,计算结果 int 整数
    String 类重写了hashCode() 方法,见源码
  4. 哈希表的存储过程
    存取原理:
    每存入一个新的元素都要走以下三步:
  5. 首先调用本类的 hashCode() 方法算出哈希值
  6. 在容器中找是否与新元素哈希值相同的老元素,如果没有直接存入,如果有转到第三步
  7. 新元素会与该索引位置下的老元素利用 equals 方法一一对比,一旦 新元素.equals(老元素),返回 true,停止对比,说明重复,不再存入,如果与该索引位置下的老元素都通过 equals 方法对比返回 false,说明没有重复,存入

哈希表

哈希表的存储过程

  1. 哈希表的存储自定义对象
    自定义对象需要重写 hashCode() 和 equals(),来保证存入对象的不重复
    //重写hachCode() 方法
    public int hashCode(){
    return name.hashCode() +age +id; //算法为name的hashCode值+age+id
    }
    //重写equals
    public boolean equals(Object obj){
    if(this == obj)
    return true;
    if(obj == null)
    return false;
    if(obj instanceof Student){
    Student s = (Student)obj;
    return name.equals(s.name) && age == s.age && id == s.id;
    }
    return false;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
  2. LinkedHashSet 集合
    LinkedHashSet 基于链表的哈希表实现,继承自 HashSet

LinkedHashSet 自身特性:

具有顺序,存储和取出的顺序相同的,线程不安全,运行速度块

public class LinkedHashSetDemo {
public static void main(String[] args) {
LinkedHashSet link = new LinkedHashSet();
link.add(123);
link.add(44);
link.add(33);
link.add(33);
System.out.println(link);
}
}
1
2
3
4
5
6
7
8
9
10
7. ArrayList,HashSet 判断对象是否重复的原因
ArrayList 的 contains()原理:底层依赖于equals()
ArrayList的 contains方法 调用时,传入的元素的调用 equals方法 依次与集合中的旧元素所比较,从而根据返回的布尔值判断是否有重复元素。
此时,当ArrayList存放自定义类型时,由于自定义类型在未重写equals方法前, 判断是否重复的依据是地址值,所以如果想根据内容判断是否为重复元素,需要重写元素的 equals方法。

HashSet 的 add() 和 contains() 底层都依赖hashCode()与 equals()
Set集合不能存放重复元素,其添加方法在添加时会判断是否有重复元素,有重复不添加,没重复则添加。
HashSet集合由于是无序的,其判断唯一的依据是元素类型的hashCode与equals方法的返回结果。规则如下:

  1. 先判断新元素与集合内已经有的旧元素的HashCode值
  2. 如果不同,说明是不同元素,添加到集合。
  3. 如果相同,再判断equals比较结果。返回true则相同元素;返回false则不同元素,添加到集合。
    所以,使用HashSet存储自定义类型,如果没有重写该类的 hashCode()与equals(),则判断重复时,使用的是地址值,如果想通过内容比较元素是否相同,需要重写该元素类的 hashcode()与equals()。

七、TreeSet
1.概述
Set 的另外一种实现,底层由 红黑树 实现;也就是说TreeSet会根据元素的大小关系,将元素默认从小到大排列

特点:

元素无序(迭代或者存储顺序和插入顺序)

不能存储重复元素

没有位序

Comparator comparator();如果TreeSet采用了定制排序,则该方法返回定制排序所使用 Comparator;如果TreeSet采用了自然排序,则返回null;

  1. TreeSet如何实现,不能存储重复元素
    其实,在真正的添加元素,treeset 的 add方法 会搜索整颗红黑树(这个元素值,是否已经存在于当前集合,如果存在,则不添加,不存在,就添加)
  2. 向TreeSet中放入,自定义的类的对象
    如果试图把一个对象添加到 TreeSet 时,则该对象的类必须实现Comparable接口,否则程序会抛出异常 java.lang.ClassCastException
    现象:直接向一个 TreeSet 中放入自定义类型的对象,发现直接抛出异常
    原因:TreeSet 不知道如何对自定义的类对象进行排序,不像字符串可以根据字典顺序

如何向TreeSet中放入自定义类型的对象?
通过某种方式告诉 TreeSet 我们 自定义对象的比较规则

如何自定义比较规则?
第一种方式:放入TreeSet 中的元素实现Comparable接口,根据 CompareTo 方法来指定比较规则:比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。负整数 -> 小于,0 -> 等于,正整数 -> 大于
//compareTo方法
@Override
public int compareTo(Student o) {
int result;
if(age == o.age) {
//当两个同学的年龄形同的时候,进一步按照名字排序
result = name.compareTo(o.name);
} else if(age > o.age) {
result = 100;
} else {
result = -34;
}
return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
第二种方式:给 TreeSet 对象定义比较器Comparator
//通过比较器,来制定比较的规则
TreeSet students = new TreeSet<>(new Comparator() {
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
});
1
2
3
4
5
6
7
4. 注意事项
约定俗成:一旦元素添加到 TreeSet 之后,禁止修改TreeSet中的元素值
原因:修改完TreeSet中的对象后,TreeSe t不会重新调整该元素在树中的位置

Java 进阶:集合框架2相关推荐

  1. java三大集合框架(面试知识储备精华篇)

    java三大集合框架 :  set  list   map 如上图 set list 都属于collection的子接口(collection为顶层接口) Map 不属于collection接口 Se ...

  2. java基础—集合框架

    java基础-集合框架 JDK1.2开始引入了集合框架的概念,以弥补java中只有数组这种容器的单一问题,这些框架多数由接口构成,另外也包含了一些对于接口实现的类,其中这些接口的最上层接口为java. ...

  3. java之集合框架一Collection接口

    1.集合的由来: 我们学习的是面向对象的语言.而面向对象语言对事物的描述是通过对象体现的.为了方便对多个对象进行操作,我们就必须把多个对象进行存储.而要想存储多个对象,就不能是一个基本的变量,而应该是 ...

  4. Java 容器集合框架概览

    Java Collections Framework 集合的概念 集合collection,有时叫做容器container,把多个元素组成一个单元. 早期的Java (pre-1.2) 中包含了Vec ...

  5. [转载]Java-集合框架完全解析

    在简书上看到一篇介绍Java集合框架的文章,写得挺详细的,http://www.jianshu.com/p/63e76826e852这是原文地址. 数据结构是以某种形式将数据组织在一起的集合,它不仅存 ...

  6. Java学习----集合框架总结

    集合框架总结: Collection接口:Set接口:HashSet//对象必须实现hashCode方法,元素没有顺序呢,效率比LinkedHashSet高LinkedHashSet//是HashSe ...

  7. Java基础-------集合框架

    一,集合简介 1.1 集合由来: 对象的存储:①数组(基本数据类型  & 引用数据类型)  ②集合(引用数据类型)     >数组存储数据的弊端:长度一旦初始化以后,就不可变:真正给数组 ...

  8. 【JAVA】集合框架及复杂度

    初识数据结构 补充 一.初识集合框架 1. 什么是集合框架 2. 集合框架的重要性 3. 背后所涉及的数据结构以及算法 二.时间和空间复杂度 1.如何衡量一个算法的复杂度 2. 算法效率 3. 时间复 ...

  9. Java基础—集合框架(三)

    一Map集合 二Map扩展知识 集合框架(三) 一.Map集合 1.概述 Map集合用于存储键值对,且它保证键的唯一性,并且每个键最多只能映射一个值.Map集合是Set集合的底层实现,其和Collec ...

  10. java进阶----集合

    1. 集合弥补了数组的缺陷,它比数组更灵活实用,而且不同的集合适用于不同场合. 2. Java集合框架共有3大类接口,即Map接口.List接口和Set接口. 3. ArrayList和数组采用相同的 ...

最新文章

  1. [USACO 1.3.3]Calf Flac
  2. java不进入for_为什么阿里巴巴Java开发手册中强制要求不要在foreach循环里进行元素的remove和add操作?...
  3. 如何高效学习web_使用高效的Web工具改善您的业务
  4. C语言中的空字符'\0'
  5. HUST 1585 排队
  6. .net winform 里控件的Dock属性(Dock的Z 顺序停靠)
  7. 编译原理完整学习笔记(八):目标代码生成
  8. [Hadoop]-Yarn-调度器篇
  9. ie支持html5代码,使用 HTML5 Shiv 让 IE 支持 HTML5
  10. HTML插入Flash的全兼容完美解决方案-SWFObject
  11. java毕业设计易医就医购药交互平台Mybatis+系统+数据库+调试部署
  12. 知乎被爆裁员20%锤子60%,BAT裁员缩招为啥急于否认?
  13. 北风:个人如何在职场中野蛮生长
  14. 关于身份证号或者手机号,密码 隐藏中间几位数字
  15. ribbonmq超时配置_使用RabbitMQ实现订单超时取消(延迟队列)
  16. (javascript)(基础知识+实例) 15.JSON,对象克隆,正则表达式
  17. c语言求最大值 若有多个最大,二个随机变量的最大值与最小值分布的求法.pdf
  18. 出现nginx: [emerg] unknown directive “]“ in /usr/local/openresty/nginx/conf/nginx.conf:74
  19. 北京工作居住证与北京居住证的区别
  20. echarts markPoint 柱形图中添加图片

热门文章

  1. 【java基础知识】编写数据库连接池
  2. java中“53”个关键字(含2个保留字)
  3. js创建,删除,读取文件目录_note
  4. php 检测变量中的回车键_PHP 的变量类型,变量检测
  5. android数据库开发案例教程,Android Studio项目开发教程 第6章 数据库编程(30页)-原创力文档...
  6. notes java api_如何使用Java来调用Notes API发送邮件(包括附件)
  7. 手机支持html5绘图性能,【高级系列】Canvas绘制性能专题
  8. 文本编辑软件哪个好_过年倒计时软件哪个好 过年倒计时软件推荐
  9. solr5 导入oracle,Solr7使用Oracle数据源导入+中文分词
  10. iphone输入法换行_【每日一技】iPhone输入法不能换行的痛点,用这招0.5秒解决