集合
一、collection接口
collection接口的子类都有的方法:
- add(),无参的添加方法,返回Boolean,表示是否添加成功
一)list 有序可重复
1.ArrayList
方法
方法名 | 参数列表 | 返回值 | 方法含义 | 注意事项 |
---|---|---|---|---|
---------增----------- | ||||
add | 元素e | boolean(是否添加成功) | 添加元素至集合末尾 | 返回值永远为true |
add | 索引,e | 添加元素e至集合指定索引位置 | 不会替换掉原来在该索引位置的元素,而是插入这个位置 | |
---------删----------- | ||||
remove | 索引 | 被删除的元素 | 删除指定索引位置的元素 | 可以用来保存以便利用/归还被删除的元素 整数类型集合,当参数放整数时视为下标而不是元素 |
remove | 元素e | Boolean(是否删除成功) | 删除集合中首次出现的那个元素e | 只删除首次出现的 |
---------改----------- | ||||
set | 索引,e | 被替换的元素 | 用元素e替换指定索引位置的元素 | |
---------查----------- | ||||
get | 索引 | 索引位置的元素 | 获得指定位置的元素值 | |
---------其他----------- | ||||
size | 集合长度 | 获得指定位置的元素值 | ||
indexOf | 元素e | 索引 | 从前往后查找指定元素的第一个下标 | |
lastIndexOf | 元素e | 索引 | 从后往前查找指定元素的第一个下标 | |
---------集合与集合间----------- | ||||
retainAll | 集合list2 | Boolean(对象是否变化) | 保留对象和参数的交集 | |
removeAll | 集合list2 | Boolean(对象是否变化) | 移除对象和参数的交集 | |
containsAll | 集合list2 | Boolean(是否包含) | 判断对象是否包含参数中的所有元素 | 忽视下标,只看元素是否相等 |
数组、集合、字符串的一般规则:
给定元素查找下标,不存在该元素会返回-1;给定下标查找元素,不存在则会报该下标越界异常;
集合嵌套
-
可以嵌套任何类型(集合套集合、套自定义数据类型、套数组)
-
嵌套集合后改变小集合内的数据:
向内部的小集合改变元素,一定会改变到大集合,无论此时小集合是否已经被添加至大集合; 因为集合是引用数据类型,操作的是内存中的地址,多层嵌套之后最终指向的还是地址值; 所以只要地址中内容改变,指向该地址的变量都会改变(即最外层的大集合也会改变);
public static void main(String[] args) {
List<List<String>> list=new ArrayList<>();
List<String> l1=new ArrayList<>();
List<String> l2=new ArrayList<>();
list.add(l1);
list.add(l2);
l1.add("A");
l1.add("C");
l2.add("D");
System.out.println(list.get(1).get(0));//可以输出D
}
- 嵌套集合的遍历:
嵌套循环(普通for/增强for)
public static void main(String[] args) {
List<List<String>> list=new ArrayList<>();
List<String> l1=new ArrayList<>();
List<String> l2=new ArrayList<>();
list.add(l1);
list.add(l2);
l1.add("A");
l1.add("C");
l2.add("D");
l2.add("1");
l2.add("5");
for(int j=0;j<list.size();j++){//普通for
for(int i=0;i<list.get(j).size();i++){
System.out.print(list.get(j).get(i));
}
System.out.println();
}
for(List<String> l:list){//增强for
for(String s:l){
System.out.print(s);
}
System.out.println();
}
}
//输出都是:
//AC
//D15
2.LinkedList与ArrayList
用法:一致
类型 | 底层数据结构 | 查找 | 增删 | 应用场景 |
---|---|---|---|---|
ArrayList | 数组 | 查找快(有索引) | 增删慢 向数组的指定索引处增加新元素:①创建长度为原数组长度+1的新数组②旧数组中元素依次放置入新数组的0-索引-1③将新元素放入索引值处④将原数组的剩余元素继续依次放入新数组 (直接在尾部追加并不慢) | 查询动作多的场景,如购物(浏览>增删购物车)、微信(查看好友列表>删除好友添加好友次数) |
Linkedlist | 链表 | 查询慢(存储乱) | 增删快 向数组的指定索引处增加新元素:①找到指定位置及其前面的元素②更改2个元素的指向 | 增删动作多的场景 |
3.for循环遍历list问题
- 遍历过程:普通for/增强for
public static void main(String[] args) {
List<String> l1=new ArrayList<>();
l1.add("A");
l1.add("A");
l1.add("B");
l1.add("C");
for(int i=0;i<l1.size();i++){
if(l1.get(i).equals("A")){
l1.remove(i);
//i--;
//因为删除掉i位置的元素之后,下一个元素就补位到了i位置
//此时i++会直接跳过这个向前补了一位的元素,故当删除了,i就不应该++(用--抵消)
}
}
System.out.println(l1);
}
二)set 不可重复
HashSet | LinkedHashSet | TreeSet | |
---|---|---|---|
底层 | 哈希表(1.7以后哈希表+红黑树) | 链表+哈希表 | 树 |
是否有序 | 存取无序 | 存取有序 | 存取无序 |
是否可重复 | 不可重复 | 不可重复 | 不可重复 |
性能 | 最优 |
树
从根节点比较,与当前节点相等放当前节点(覆盖,所以不会重复);比当前节点大放左下边,比当前节点小放右下边
例:一组数据的存储:3 4 11 8 22 4 45 9 6 7
哈希表
数组+链表(1.7以后+红黑树)
- 添加数据
- 获取数据的哈希值
- 表中是否已有这个哈希值(HashCode≈引用类型在堆中的16进制地址值转换为10进制)
- 已有:调用equals:true则不再放置(所以不会重复);false则根据算法决定放置位置
- 没有——根据算法决定放置位置
重复值问题——重写HashCode 和 equals 方法
字面值相同但未被去重
场景
由于存储在了2个自定义类型的对象中,地址不同,故哈希值不同;
调用equals时,父类原始equals方法仍只是比较地址值,返回false;
解决
重写HashCode令其return一个固定的int值;
重写equals令其根据自定义类型的某些属性比较
一般先:
判断是否this==参数对象;
判断对象的String类型属性是否有为空的(避免到时候用该属性值调equals,出现空指针异常),若有则直接返回false,若没有则返回其equals比较结果
this.字符属性 == null? false: this.字符属性.getname().equals(obj.getname())
字面值不同但地址相同
哈希冲突,通过带秘钥的哈希函数等方式已被优化
二、map接口
双列的,键不重复,值可以重复,1键只能对应1值
方法名 | 功能 | 返回值 | 参数列表 | 注意事项 |
---|---|---|---|---|
put | 在map中存储(或覆盖)键值对的映射关系 | 被覆盖掉的值(如果没有覆盖谁,返回Null) | 键,值 | 没有任何重载 |
remove | 模糊删除键值对 | 被删除的值 | 键 | |
remove | 精确删除键值对 | Boolean | 键,值 | 需要找到键值都符合参数的键值对才删除,否则不删除 |
replace | 模糊替换指定键上的旧值 | 被替换的值(null) | 键,新值 | :— |
replace | 精确替换指定键值对上的旧值 | Boolean | 键,旧值,新值 | 需要找到键值都符合参数的键值对才替换,否则不替换 |
get | 获取指定键上的值 | 值(没有这个键则返回null) | 键 | map没有下标概念,只有键 |
entrySet | 获取集合中的全部键值对关系 | 存放键值对关系的Set集合 | ||
keySet | 获取集合中的全部键 | 存放键的Set集合 |
一)HashMap 无序
二)LinkedHashMap 有序
三)遍历map
遍历方式 | 可应用场景 | 注意事项 |
---|---|---|
普通for循环 | 遍历数组、list 遍历字符串 | 不可以遍历set、map(因为这两个没有下标) |
foreach | 遍历数组、list 遍历set | 不可以遍历字符串、map;只能遍历数组或iterable接口的实例(collection接口继承了iterable接口) |
foreach+EntrySet/KeySet | 遍历map | |
iterator+EntrySet/KeySet | 遍历map |
foreach+EntrySet/KeySet
通过entrySet/keySet方法,获得映射关系的集合/键的集合,遍历返回的集合中的元素,调用get、getKey 和getValue方法获取所有的键和值。
for(int e:people.keySet()){
System.out.print(e+"-"+people.get(e));
}
for(Entry<Integer, String> e:people.entrySet()){
System.out.print(e.getKey()+"-"+e.getValue());
}
iterator+EntrySet/KeySet
迭代器iterator
含义:对collection进行迭代的接口
使用对象:collection(不能直接遍历map)
public static void main(String[] args) {
Map<String,String> m1=new HashMap<>();
m1.put("AA","123");
m1.put("AB","213");
m1.put("BA","253");
m1.put("BB","423");
Set<Map.Entry<String,String>> s1=m1.entrySet();//获取set集合
Iterator<Map.Entry<String,String>> it=s1.iterator();//获取Set集合的迭代器对象
while (it.hasNext()){
//while的好处:书写方面
//循环条件:有没有下一个元素可获取,没有就结束
System.out.println(it.next());//获取这个"下一个"元素
System.out.println(it.next().getKey()+":"+it.next().getValue());
//执行结果有误,因为每次next,迭代器的指针都会向后移动一位;
//故获取的是下一个元素的key和下下个元素的value
}
for(Iterator<Map.Entry<String,String>> it2=s1.iterator();it2.hasNext();){
//for的好处:it2对象及时释放
System.out.println(it2.next());
}
}
迭代器可以 边遍历边删除元素 !
不能用集合本身进行增删改
集合本身增删改会导致迭代器指向的数据源变化,迭代器发生concurrentModificationException
迭代器的iterator操作的是迭代器副本,不会改变数据源,最后再返回给数据源,故不会异常;
但iterator只有移除功能,如果希望添加(add )可以使用 ListIterator创建Iterator对象;
ListIterator有一些返回index、反向遍历previous相关功能;
it.next();指针向后移动,移动到下一个元素和下下一个元素之间,返回下一个元素内容
it.previous();指针向前移动,移动到下(前)一个元素和下(前)下(前)一个元素之间,返回下(前)一个元素内容
it.hasprevious();返回Boolean
it.hasNext();返回Boolean
it.nextIndex();返回int,下一个元素下表
it.PreviousIndex();返回int,上一个元素下标
四)map的排序
map本身是无序的,set(除了linkedhashset)也是无序的,都必须转换成list,然后重写comparable接口的compareTo方法~
Set<String > s1=new HashSet<>();
ArrayList <String> a1=new Arraylist<>(s1);
Collections.sort(a1);
-----------------------------
Map<String,String> s1=new HashMap<>();
ArrayList<Entry<String,String>> a1= new ArrayList<>(s1.entrySet());
Collections.sort(a1);
- 调用 entrySet方法 或 keySet方法
- 调用arraylist的构造方法(将set集合作为参数的),创建list对象
- 使用collections工具类的排序方法,将list对象传入,并重写比较器(比较器的参数类型为 Entry<K, V> 或 K)
排序的结果也只能在list中存储和输出,不可能在放回map的,因为map存取无序,排好序放进去的也可能再遍历出来又是底层算法决定的顺序了。
三、collections工具类
方法名 | 功能 | 返回值 | 参数列表 | 注意事项 |
---|---|---|---|---|
addAll | 向集合中添加N多数据元素 | collection集合 | collection集合,元素1,元素2… | |
reverse | 倒序排列 | list类型的集合 | list集合 | 只有list保证顺序,可以倒序 |
max | 求最大值 | 集合中数据的类型的排序后的最大值 | collection类型的集合 | (数字、字典顺序、ASCII码的顺序) |
min | 求最小值 | 同上 | collection类型的集合 | (数字、字典顺序、ASCII码的顺序) |
shuffle | 打乱 | list集合 | list集合 | |
replaceAll | :— | :— | :— | 集合中的东西全部替换掉 |
swap | 交换集合中2个指定位置的元素 | list集合 | list集合,需要交换的下标1,需要交换的下标2 | |
sort | 排序 | list集合 | list集合 | (数字、字典顺序、ASCII码的顺序) |
clear | 清空整个集合 | |||
containsKey | 判断集合中是否有指定键 | Boolean | 键 | |
containsValue | 判断集合中是否有指定的值 | Boolean | 值 | |
Values | 获取集合中所有的值 | 集合中的值的类型的集合 | collection集合 | 不能写collection的子类,除非强转 |
equals | 比较2个集合元素是否个数、内容完全一致(有序的列表包括顺序一致) | Boolean | 不是比较地址值 | |
:---- | :— | :— | :— | :— |
:---- | :— | :— | :— | :— |
方法名 | 使用场景 | 返回值 | 参数列表 | 其他注意事项 |
compareTo | comparable接口的方法,集合的元素之间按属性比较 | 调用sort时可以使用匿名多态写法,创建接口的子类对象并重写compareTo方法,返回排序完成的集合 | 泛型的类型参数 | 降序:返回参数对象.属性-this.属性;升序:返回this.属性-参数对象.属性 |
compareTo | 字符串之间比较 | 长度一样比较每个字符的字典位置,长度不同比较长度,返回其差值 | 字符串1 ,字符串2 | |
compareTo | 日期之间比较 | 返回日期在参数之前还是之后(-1 0 1) | 日期对象 |