集合————示例详解
集合示例:
①、Iterator:迭代器,它是Java集合的顶层接口(不包括 map 系列的集合,Map接口 是 map 系列集合的顶层接口)
Object next():返回迭代器刚越过的元素的引用,返回值是 Object,需要强制转换成自己需要的类型
boolean hasNext():判断容器内是否还有可供访问的元素
void remove():删除迭代器刚越过的元素
所以除了 map 系列的集合,我们都能通过迭代器来对集合中的元素进行遍历。
注意:我们可以在源码中追溯到集合的顶层接口,比如 Collection 接口,可以看到它继承的是类 Iterable
那这就得说明一下 Iterator 和 Iterable 的区别:
Iterable :存在于 java.lang 包中。
我们可以看到,里面封装了 Iterator 接口。所以只要实现了只要实现了Iterable接口的类,就可以使用Iterator迭代器了。
Iterator :存在于 java.util 包中。核心的方法next(),hasnext(),remove()。
这里我们引用一个Iterator 的实现类 ArrayList 来看一下迭代器的使用:暂时先不管 List 集合是什么,只需要看看迭代器的用法就行了
1 //产生一个 List 集合,典型实现为 ArrayList。
2 List list = new ArrayList();
3 //添加三个元素
4 list.add("Tom");
5 list.add("Bob");
6 list.add("Marry");
7 //构造 List 的迭代器
8 Iterator it = list.iterator();
9 //通过迭代器遍历元素
10 while(it.hasNext()){
11 Object obj = it.next();
12 System.out.println(obj);
13 }
②、Collection:List 接口和 Set 接口的父接口
看一下 Collection 集合的使用例子:
1 //我们这里将 ArrayList集合作为 Collection 的实现类
2 Collection collection = new ArrayList();
3
4 //添加元素
5 collection.add("Tom");
6 collection.add("Bob");
7
8 //删除指定元素
9 collection.remove("Tom");
10
11 //删除所有元素
12 Collection c = new ArrayList();
13 c.add("Bob");
14 collection.removeAll(c);
15
16 //检测是否存在某个元素
17 collection.contains("Tom");
18
19 //判断是否为空
20 collection.isEmpty();
21
22 //利用增强for循环遍历集合
23 for(Object obj : collection){
24 System.out.println(obj);
25 }
26 //利用迭代器 Iterator
27 Iterator iterator = collection.iterator();
28 while(iterator.hasNext()){
29 Object obj = iterator.next();
30 System.out.println(obj);
31 }
③、List :有序,可以重复的集合。
由于 List 接口是继承于 Collection 接口,所以基本的方法如上所示。
1、List 接口的三个典型实现:
①、List list1 = new ArrayList();
底层数据结构是数组,查询快,增删慢;线程不安全,效率高
②、List list2 = new Vector();
底层数据结构是数组,查询快,增删慢;线程安全,效率低,几乎已经淘汰了这个集合
③、List list3 = new LinkedList();
底层数据结构是链表,查询慢,增删快;线程不安全,效率高
怎么记呢?我们可以想象:
数组就像身上编了号站成一排的人,要找第10个人很容易,根据人身上的编号很快就能找到。但插入、删除慢,要望某个位置插入或删除一个人时,后面的人身上的编号都要变。当然,加入或删除的人始终末尾的也快。
链表就像手牵着手站成一圈的人,要找第10个人不容易,必须从第一个人一个个数过去。但插入、删除快。插入时只要解开两个人的手,并重新牵上新加进来的人的手就可以。删除一样的道理。
2、除此之外,List 接口遍历还可以使用普通 for 循环进行遍历,指定位置添加元素,替换元素等等。
1 //产生一个 List 集合,典型实现为 ArrayList
2 List list = new ArrayList();
3 //添加三个元素
4 list.add("Tom");
5 list.add("Bob");
6 list.add("Marry");
7 //构造 List 的迭代器
8 Iterator it = list.iterator();
9 //通过迭代器遍历元素
10 while(it.hasNext()){
11 Object obj = it.next();
12 //System.out.println(obj);
13 }
14
15 //在指定地方添加元素
16 list.add(2, 0);
17
18 //在指定地方替换元素
19 list.set(2, 1);
20
21 //获得指定对象的索引
22 int i=list.indexOf(1);
23 System.out.println("索引为:"+i);
24
25 //遍历:普通for循环
26 for(int j=0;j<list.size();j++){
27 System.out.println(list.get(j));
28 }
④、Set:典型实现 HashSet()是一个无序,不可重复的集合
1、Set hashSet = new HashSet();
①、HashSet:不能保证元素的顺序;不可重复;不是线程安全的;集合元素可以为 NULL;
②、其底层其实是一个数组,存在的意义是加快查询速度。我们知道在一般的数组中,元素在数组中的索引位置是随机的,元素的取值和元素的位置之间不存在确定的关系,因此,在数组中查找特定的值时,需要把查找值和一系列的元素进行比较,此时的查询效率依赖于查找过程中比较的次数。而 HashSet 集合底层数组的索引和值有一个确定的关系:index=hash(value),那么只需要调用这个公式,就能快速的找到元素或者索引。
③、对于 HashSet: 如果两个对象通过 equals() 方法返回 true,这两个对象的 hashCode 值也应该相同。
1、当向HashSet集合中存入一个元素时,HashSet会先调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据hashCode值决定该对象在HashSet中的存储位置
1.1、如果 hashCode 值不同,直接把该元素存储到 hashCode() 指定的位置
1.2、如果 hashCode 值相同,那么会继续判断该元素和集合对象的 equals() 作比较
1.2.1、hashCode 相同,equals 为 true,则视为同一个对象,不保存在 hashSet()中
1.2.2、hashCode 相同,equals 为 false,则存储在之前对象同槽位的链表上,这非常麻烦,我们应该约束这种情况,即保证:如果两个对象通过 equals() 方法返回 true,这两个对象的 hashCode 值也应该相同。
注意:每一个存储到 哈希 表中的对象,都得提供 hashCode() 和 equals() 方法的实现,用来判断是否是同一个对象
对于 HashSet 集合,我们要保证如果两个对象通过 equals() 方法返回 true,这两个对象的 hashCode 值也应该相同。
LinkedHashSet的特征
LinkedHashSet是HashSet的一个子类,LinkedHashSet也根据HashCode的值来决定元素的存储位置,但同时它还用一个链表来维护元素的插入顺序,插入的时候即要计算hashCode又要维护链表,而遍历的时候只需要按链表来访问元素。查看LinkedHashSet的源码发现它是样的
public class LinkedHashSet<E>
extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable {
private static final long serialVersionUID = -2851667679971038690L;
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}
....
在JAVA8中, LinkedHashSet没有定义任何方法,只有四个构造函数,它的构造函数调用了父类(HashSet)的带三个参数的构造方法,父类的构造函数如下
/**
* Constructs a new, empty linked hash set. (This package private
* constructor is only used by LinkedHashSet.) The backing
* HashMap instance is a LinkedHashMap with the specified initial
* capacity and the specified load factor.
*
* @param initialCapacity the initial capacity of the hash map
* @param loadFactor the load factor of the hash map
* @param dummy ignored (distinguishes this
* constructor from other int, float constructor.)
* @throws IllegalArgumentException if the initial capacity is less
* than zero, or if the load factor is nonpositive
*/
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
由此可知,LinkedHashSet本质上也是从LinkedHashMap而来,LinkedHashSet的所有方法都继承自HashSet, 而它能维持元素的插入顺序的性质则继承自LinkedHashMap.
下面是一个LinkedHashSet维持元素插入顺序的例子
import java.util.LinkedHashSet;
import java.util.Set;
/**
* ClassName: LinkedHashSets
* Description:
* date: 2019-11-20 17:18
*
* @author chengluchao
* @since JDK 1.8
*/
public class LinkedHashSets {
public static void main(String[] args) {
Set set = new LinkedHashSet();
set.add("abc");
set.add("efg");
set.add("hjk");
System.out.println(set);
set.remove(new String("abc"));
set.add("abc");
System.out.println(set);
}
}
输入如下
[abc, efg, hjk]
[efg, hjk, abc]
TreeSet类的特征
TreeSet实现了SortedSet接口,顾名思义这是一种排序的Set集合,查看jdk源码发现底层是用TreeMap实现的,本质上是一个红黑树原理。 正因为它是排序了的,所以相对HashSet来说,TreeSet提供了一些额外的按排序位置访问元素的方法,例如first(), last(), lower(), higher(), subSet(), headSet(), tailSet().
TreeSet的排序分两种类型,一种是自然排序,另一种是定制排序。
自然排序(在元素中写排序规则)
TreeSet 会调用compareTo方法比较元素大小,然后按升序排序。所以自然排序中的元素对象,都必须实现了Comparable接口,否则会抛出异常。对于TreeSet判断元素是否重复的标准,也是调用元素从Comparable接口继承而来额compareTo方法,如果返回0则是重复元素(两个元素I相等)。Java的常见类都已经实现了Comparable接口,下面举例说明没有实现Comparable存入TreeSet时引发异常的情况。
import java.util.Set;
import java.util.TreeSet;
/**
* ClassName: TestSets
* Description: Tree自然排序
* date: 2019-11-20 17:27
*
* @author chengluchao
* @since JDK 1.8
*/
public class TestSets {
public static void main(String[] args) {
Set set = new TreeSet();
set.add(new Err());
set.add(new Err());
set.add(new Err());
System.out.println(set);
}
}
class Err {
}
运行程序会抛出如下异常
Exception in thread "main" java.lang.ClassCastException: clc.Err cannot be cast to java.lang.Comparable
at java.util.TreeMap.compare(TreeMap.java:1294)
at java.util.TreeMap.put(TreeMap.java:538)
at java.util.TreeSet.add(TreeSet.java:255)
at clc.TestSets.main(TestSets.java:17)
将上面的Err类实现Comparable接口之后程序就能正常运行了
class Err implements Comparable{
@Override
public int compareTo(Object o) {
return 0;
}
}
还有个重要问题是,因为TreeSet会调用元素的compareTo方法,这就要求所有元素的类型都相同,否则也会发生异常。也就是说,TreeSet只允许存入同一类的元素。例如下面这个例子就会抛出类型转换异常
public static void main(String[] args) {
Set set = new TreeSet();
set.add(1);
set.add("2");
System.out.println(set);
}
运行结果
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.util.Date
at java.util.Date.compareTo(Date.java:131)
at java.util.TreeMap.put(TreeMap.java:568)
at java.util.TreeSet.add(TreeSet.java:255)
at clc.TestSets.main(TestSets.java:19)
定制排序(在集合中写排序规则)
TreeSet还有一种排序就是定制排序,定制排序时候,需要关联一个Comparator对象,由Comparator提供排序逻辑。下面就是一个使用Lambda表达式代替Comparator对象来提供定制排序的例子。下面是一个定制排序的列子
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
/**
* ClassName: TestSets
* Description: Tree自然排序
* date: 2019-11-20 17:27
*
* @author chengluchao
* @since JDK 1.8
*/
public class TestSets {
public static void main(String[] args) {
Set set = new TreeSet(new MyCommpare());
set.add(new M(5));
set.add(new M(3));
set.add(new M(9));
System.out.println(set);
}
}
class M {
int age;
public M(int age) {
this.age = age;
}
}
class MyCommpare implements Comparator {
@Override
public int compare(Object o1, Object o2) {
M m1 = (M) o1;
M m2 = (M) o2;
return m1.age > m2.age ? 1 : m1.age < m2.age ? -1 : 0;
}
}
当然将Comparator直接写入TreeSet初始化中也可以。如下。
import org.junit.Test;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
/**
* ClassName: TestSets
* Description: Tree自然排序
* date: 2019-11-20 17:27
*
* @author chengluchao
* @since JDK 1.8
*/
public class TestSets {
public static void main(String[] args) {
Set set = new TreeSet(new MyCommpare());
set.add(new M(5));
set.add(new M(3));
set.add(new M(9));
System.out.println(set);
}
/**
* Description: 将Comparator直接写入TreeSet初始化中1
*
* @method: testTreeSet
* @author: chengluchao
* @date: 2019-11-21 09:41
* @param:
* @return:
*/
@Test
public void testTreeSet() {
Set set = new TreeSet(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
M m1 = (M) o1;
M m2 = (M) o2;
return m1.age > m2.age ? 1 : m1.age < m2.age ? -1 : 0;
}
});
set.add(new M(5));
set.add(new M(3));
set.add(new M(9));
System.out.println(set);
}
/**
* Description: 将Comparator直接写入TreeSet初始化中
*
* @method: testTreeSetLam
* @author: chengluchao
* @date: 2019-11-21 09:41
* @param:
* @return:
*/
@Test
public void testTreeSetLam() {
Set set = new TreeSet((o1, o2) -> {
M m1 = (M) o1;
M m2 = (M) o2;
return m1.age > m2.age ? 1 : m1.age < m2.age ? -1 : 0;
});
set.add(new M(5));
set.add(new M(3));
set.add(new M(9));
System.out.println(set);
}
}
class M {
int age;
public M(int age) {
this.age = age;
}
}
class MyCommpare implements Comparator {
@Override
public int compare(Object o1, Object o2) {
M m1 = (M) o1;
M m2 = (M) o2;
return m1.age > m2.age ? 1 : m1.age < m2.age ? -1 : 0;
}
}
class Err implements Comparable {
@Override
public int compareTo(Object o) {
return 0;
}
集合————示例详解相关推荐
- redis储存实体类对象_Redis如何存储对象与集合示例详解
前言 大家都知道在项目中,缓存以及mq消息队列可以说是不可或缺的2个重要技术.前者主要是为了减轻数据库压力,大幅度提升性能.后者主要是为了提高用户的体验度,我理解的是再后端做的一个ajax请求(异步) ...
- java网络编程阻塞_Java网络编程由浅入深三 一文了解非阻塞通信的图文代码示例详解...
本文详细介绍组成非阻塞通信的几大类:Buffer.Channel.Selector.SelectionKey 非阻塞通信的流程ServerSocketChannel通过open方法获取ServerSo ...
- go语言字符串换行_Go语言中的字符串处理方法示例详解
1 概述 字符串,string,一串固定长度的字符连接起来的字符集合.Go语言的字符串是使用UTF-8编码的.UTF-8是Unicode的实现方式之一. Go语言原生支持字符串.使用双引号(" ...
- 史上最易懂——ReactNative分组列表SectionList使用详情及示例详解
React Native系列 <逻辑性最强的React Native环境搭建与调试> <ReactNative开发工具有这一篇足矣> <解决React Native un ...
- python中3or5什么意思_示例详解Python3 or Python2 两者之间的差异
每门编程语言在发布更新之后,主要版本之间都会发生很大的变化. 在本文中,Vinodh Kumar 通过示例解释了 Python 2 和 Python 3 之间的一些重大差异,以帮助说明语言的变化. 本 ...
- php reactphp wss_workerman的基本用法(示例详解)
workerman是什么? Workerman是一个异步事件驱动的PHP框架,具有高性能,可轻松构建快速,可扩展的网络应用程序.支持HTTP,Websocket,SSL和其他自定义协议.支持libev ...
- python的用途实例-python assert的用处示例详解
使用assert断言是学习python一个非常好的习惯,python assert 断言句语格式及用法很简单.在没完善一个程序之前,我们不知道程序在哪里会出错,与其让它在运行最崩溃,不如在出现错误条件 ...
- 线性代数带参数的线性方程组的求法示例详解
线性方程组的求法与示例详解 线性方程组 由n个1维未知量,m个方程组成的组合叫做线性方程组. 特别的当方程组右边的值全都是0时叫做齐次线性方程组. 增广矩阵 在系数矩阵的右边添上一列,该列由线性方程组 ...
- python动态生成数据库表_Python-Flask:动态创建表的示例详解
今天小编从项目的实际出发,由于项目某一个表的数据达到好几十万条,此时数据的增删查改会很慢:为了增加提高访问的速度,我们引入动态创建表. 代码如下: from app_factory import ap ...
最新文章
- 【ASP.NET开发】ASP.NET(MVC)三层架构知识的学习总结
- childNodes详解
- GET POST方法长度限制
- .NET的委托和匿名函数应用一例
- 【Kafka】kafka 监控指标项
- xml文件查看器_万能文件查看器,一个软件打开电脑所有文件
- lte网络测试用什么软件,LTE_测试软件使用教程.doc
- 宏碁Aspire 4560试用手记
- Android 百度语音合成手把手教学
- Vue3 组件通信方式【最好用的都在这里了】
- 手机PDF文件转换成图片教程来了,PDF转换器推荐
- 初学VUE 走马灯效果
- python 移动平均线_Python中的移动平均线
- 电信光猫路由模式转桥接
- java 使用相对路径读取文件
- 电脑磁盘更改盘符时出现参数错误该如何解决。
- 大数据专栏一-全自动化在线式当当销售情况分析预测系统
- VS 关于打开程序时不是有效的Win32应用程序
- php 熊掌号api,关于熊掌号资源提交功能API接口解读
- ​海外公链集体哑火? BATJ迅雷却成为区块链3.0拓荒者 【区块链3.0一周年】
热门文章
- 唱歌如何保持高位置_声乐唱歌唱到高音如何保持高位置?
- SATA、MSATA、M.2 SATA、M.2 NVME-实物接口
- 华科跟清华计算机专业,华科+清华 VS 南大+哥大 哪个更强
- Apollo 应用与源码分析:Monitor监控-硬件监控-GPS
- Python实现AO*算法进行与或图搜索
- python爬虫之requests库的用法(超全面的爬取网页案例)
- css设置textarea宽高,怎么用CSS让textarea宽度为100%? 自适应页面
- java如何让textarea填满面板_JavaFX TextArea:如何设置制表宽度
- 12.01-内存管理_定时器的循环引用
- 【Linux】X11VNC安装指导