集合
集合类出现的原因?
面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,Java就提供了集合类。
数组和集合类有何不同?
数组虽然也可以存储对象,但长度是固定的;集合长度是可变的。
数组中可以存储基本数据类型,集合只能存储对象。
集合类的特点
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
1.Collection
概述:Collection 层次结构中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。
成员方法
操作元素:
boolean add(E e) 添加
boolean remove(Object o) 移除
void clear() 清空
boolean contains(Object o) 是否包含
boolean isEmpty() 是否为空
int size() 集合的长度
boolean addAll(Collection c) 添加所有
boolean removeAll(Collection c) 移除所有(凡是参数中包含的内容都会被移除掉)
boolean containsAll(Collection c) 是否全部包含
boolean retainAll(Collection c) 取交集
取完交集后 调用的那个集合是够发生改变
如果发生改变 返回值为true
如果没有改变 返回值为false
public static void main(String[] args) {
ArrayList cc = new ArrayList();
cc.add("三国演义");
cc.add("水浒传");
cc.add("红楼梦");
cc.add("西游记");
cc.add("西厢记");
ArrayList cc2 = new ArrayList();
cc2.add("造纸术");
cc2.add("印刷术");
cc2.add("指南针");
cc2.add("火药");
cc.addAll(cc2);
cc2.add("火药");
System.out.println(cc);//[三国演义, 水浒传, 红楼梦, 西游记, 西厢记, 造纸术, 印刷术, 指南针, 火药]
//
// cc.removeAll(cc2);
//
// System.out.println(cc);
System.out.println(cc.contains(cc2));//false
System.out.println(cc.retainAll(cc2));//true
System.out.println(cc);//[造纸术, 印刷术, 指南针, 火药]
}
遍历
Object[] toArray() 把集合转成数组,可以实现集合的遍历
Iterator iterator() 得到一个迭代器的对象
Iterator成员方法:
boolean hasNext() 判断集合中是否还有下一个元素
E next() 取出集合中的下一个元素
常见的数据结构
栈 先进后出,后进先出,进栈出栈
队列 先进先出,后进后出
数组 查找快,增删慢
链表 查找慢,增删快
树 查找慢,增删快
先序遍历,中序遍历,后序遍历
哈希表 键值对结构,通过key那value
数组的元素是单链表
2.List
概述:有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。与 set 不同,列表通常允许重复的元素。
成员方法
void add(int index,E element) 插入
E remove(int index) 把指定索引的值移除掉
E get(int index) 索取指定索引对应的元素
E set(int index,E element) 替换
ListIterator listIterator() 获取ListIterator对象,用于迭代
遍历方法:
1 转数组
2 Iterator迭代器
3 for循环
4 列表迭代器
ListIterator listIterator()
2.1ArrayList
概述:底层数据结构是数组,查询快,增删慢,线程不安全,效率高
2.2LinkList
概述:底层数据结构是链表,查询慢,增删快,线程不安全,效率高
LinkList中特有方法
addFirst/addLast: 添加头/添加尾
getFirst/getLast 获取头/获取尾
removeFirst/removeLast 移除头/移除尾
栈结构:先进后出 压栈 弹栈
队列:先进先出
增强for循环
增强for概述:
简化数组和Collection集合的遍历
格式:
for(元素数据类型 元素名 : 数组或者Collection集合) {
对元素进行你自己的操作
}
好处:简化遍历
注意事项:增强for的目标要判断是否为null
把前面的集合代码的遍历用增强for改进
可变参数
jdk5以后产生的新特性
用途:
定义方法的时候不知道该定义多少个参数
格式:
修饰符 返回值类型 方法名(数据类型… 变量名){}
注意:
这里的变量其实是一个数组
如果一个方法有可变参数,并且有多个参数,那么,可变参数必须是最后一个
一个方法中最多只能有一个可变参数
集合和数组的相互转换
数组转集合
statitc List Arrays.asList(T… t);
集合转数组
Object[] toArray();
3.Set
特点: Set中的元素是无序的(不能使用索引操作元素),元素不可重复
Collection:
List(I): 有序的,元素可重复
ArrayList
LinkedList
Set(I): 无序的(不能使用索引操作元素),元素不能重复
HashSet: 无法保证存入和取出的顺序
LinkedHashSet: 可以保证存入和取出的顺序(链表实现)
TreeSet:有序的(可以对元素排序)
不可重复性:
是由hashCode和equals方法保证的
存放元素的时候,先求出元素的hashCode,如果集合中没有这样的hashCode 值,说明该元素在集合中不存在, 可以存;有这样的hashCode,在比较equals: 如果为true: 集合中已经存在该元素,则不存,如果为false: 则可以存
3.1HashSet
概述:
不保证 set 的迭代顺序
特别是它不保证该顺序恒久不变。
HashSet如何保证元素唯一性?
底层数据结构是哈希表(元素是链表的数组),哈希表依赖于哈希值存储
添加功能底层依赖两个方法:
int hashCode()
boolean equals(Object obj)
3.2LinkedHashSet
概述:
元素有序唯一
由链表保证元素有序
由哈希表保证元素唯一
4.Map
概述:将键映射到值的对象
一个映射不能包含重复的键
每个键最多只能映射到一个值
key=value
Map接口和Collection接口的不同
Map是双列的,Collection是单列的
Map的键唯一,Collection的子体系Set是唯一的
Map集合的数据结构值针对键有效,跟值无关
Collection集合的数据结构是针对元素有效
成员方法
V put(K key,V value) 添加元素
V remove(Object key) 移除key 对应的 键值对
void clear() 清空map
boolean containsKey(Object key) 是否包含key
boolean containsValue(Object value) 是否包含value
boolean isEmpty() 是否为空
int size() 键值对的个数
遍历
keySet: 获取所有的key
entrySet: 获得所有的entry:
values: 获取所有的值
方式1:根据键找值
获取所有键的集合
遍历键的集合,获取到每一个键
根据键找值
方式2:根据键值对对象找键和值
获取所有键值对对象的集合
遍历键值对对象的集合,获取到每一个键值对对象
根据键值对对象找键和值
getOrDefault 拿着键去集合里面取值 如果有值 直接取出 如果没值 就返回默认值
4.1HashMap
键是哈希表结构,可以保证键的唯一性
4.2LinkedHashMap
Map 接口的哈希表和链接列表实现,具有可预知的迭代顺序。lMap 接口的哈希表和链接列表实现,具有可预知的迭代顺序。
泛型
泛型是从jdk5引入的新的特性,为什么要产生泛型呢,主要有以下两个原因:
- 当我们将一个对象放入集合中,集合不会记住此对象的类型,当再次从集合中取出此对象时,该对象的编译类型变成了Object类型,但其运行时类型任然为其本身类型。
- 因此,此处取出集合元素时需要人为的强制类型转化到具体的目标类型,且很容易出现“java.lang.ClassCastException”异常。
那么到底什么是泛型呢,就是所说的类型参数化,即可以象参数一样控制某种数据类型,有了泛型我们就可以指定集合中所能存储的数据类型:
注意: 泛型只在编译时期有效, 对于正确检验泛型结果后,会将泛型的相关信息擦出,也就是说,成功编译过后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段。
自定义泛型类
格式:class 类名<泛型符号>{} 符号为任意字母,常用的有T,E,K,V
自定义泛型接口
泛型接口与泛型类的定义及使用基本相同。
注意事项:
- 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中, 如果不声明泛型,如:class FruitGenerator implements Generator,编译器会报错:“Unknown class”
- 当实现泛型接口的类,传入泛型实参时, 则所有使用泛型的地方都要替换成传入的实参类型,即:InterA ,public void show (T t);中的的T都要替换成传入的String类型。
泛型方法
用于放置泛型的类型参数的尖括号应出现在方法的其他所有修饰符之后和在方法的返回类型之前,也就是紧邻返回值之前,下面的
说明:
1)public 与 返回值中间非常重要,可以理解为声明此方法为泛型方法。
2)只有声明了的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。
3)表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。
4)与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示型。
泛型通配符
泛型的通配符:
泛型通配符>
任意类型,如果没有明确,那么就是Object以及任意的Java类了
? extends E
向下限定,E及其子类
? super E
向上限定,E及其父类
注意: 泛型的通配值只能用在=的左边或者是参数列表上
5.Collections工具类
public static void sort(List list) 排序,升序
public static int binarySearch(List> list,T key) 二分查找,不存在返回负数,只能针对升序集合
public static T max(Collection> coll) 最大值
public static void reverse(List> list) 反转
public static void shuffle(List> list) 随机打乱
public static void sort(List list, Comparator super T> c) 排序,和比较器配合使用
6.比较器***(比较器)
6.1 Comparable用法
要想让一个List可以使用Collections.sort进行排序,需要要求集合中的元素所在的类实现Comparable(java.lang) 接口,实现了该接口就具备了排序的能力,才能进行排序,实现该接口我们需要重写里面的compareTo方法,该方法的主要目的就是定义排序的规则(即告诉接口按照什么规则比较大小),重写该方法时要注意,该方法的返回值是int类型,
返回值为正数,表明this中的数据大于参数中的数据, 排序时将大的数移至后面
返回值为0,表明this中的数据等于参数中的数据
返回值为负数,表明this中的数据小于参数中的数据
其实就是用this对象和参数对象做一个比较,this对象在前,就是升序,参数对象在前就是降序.
案例:实现对于List 年龄的升序
实现排序的步骤:
- 让 Animal 类实现 Comparable
- 重写compareTo 方法: 定义排序的规则
升序: this和 参数
降序: 参数和this
- Collections.sort(list); 在测试类中写
6.2Comparator用法
掌握了如何对于一个List做排序,那么就因该知道了为什么List 默认实现的是升序,就是因为Integer在实现Comparable接口的时候用的就是升序的方式,若想实现降序应该如何做?其实只需要将Integer中的compareTo方法中的两个参数调换一下位置就可以,但是由于是class文件我们不能修改.所以java为我们提供了一个外部比较器Comparator(java.util)
6.3Comparable和Comparator比较
Comparable: 内部比较器,java.lang; 如果一个List想要使用Collections.sort() 做排序,需要集合中的元素所在的类实现Comparable接口,重写compareTo:
this在前,升序; 参数在前 : 降序
Comparator: 外部比较器,java.util; 如果一个类中不能实现Comparable,或者是对应Comparable中的排序方式不满意,可以通过Comparator重新定义排序的规则,而不需要修改原有类的结构, Collections.sort(list,Comparator)//匿名内部类。
7.TreeSet,TreeMap用法
7.1TreeSet
可以对集合中的元素实现自然排序. 要想使用TreeSet对集合中的元素做排序,要求Set中的元素所在的类必须实现Comparable接口,否则会出现转型异常: com._51doit.tree.Person cannot be cast to java.lang.Comparable,TreeSet中元素不可重复: 依赖 compareTo/compare,也就是说如果compare/compareTo方法返回的结果是0,TreeSet就会认为是相同的元素,只保存一个,所以我们在使用的时候尽量不要只比较一个属性.还有TreeSet中的元素不能为null(需要使用元素调用compare/compareTo做比较,如果为空,会出现空指针异常);
7.2TreeMap
可对key这一列做自然排序,key不能重复,且不能为空(会空指针).key不能重复也是用compare/compareTo决定的
最后
感谢你看到这里,看完有什么的不懂的可以在评论区问我,觉得文章对你有帮助的话记得给我点个赞,每天都会分享java相关技术文章或行业资讯,欢迎大家关注和转发文章!