集合
集合是什么?它是一个容器,存放数据的一个容器
使用集合的目的?更方便的存储和操作数据,CRUD
集合继承结构
Collection<E>
:存放单值的最大父接口List<E>
:列表,线性表,和数组类似,List
可以动态增长,查找元素效率高,插入删除元素的效率低,因为会引起其他元素位置的改变。Set<E>
:它也是线性表,检索元素效率低,删除和插入的效率高,插入和删除不会引起元素移位。
Map<K,V>
:存放对值的最大父接口Map
,(映射)用于保存具有映射关系的数据,Map保存着两组数据,key和value,key和value都可以是任意的引用数据类型,但key不能重复。
List和Set继承Collection,但Map不是
List的简单运用
代码
public class Ch02 {
public static void main(String[] args) {
// 创建了一个ArrayList集合
// 开发中,一般情况下,使用多态创建集合(向上转型)
List<Integer> l1 = new ArrayList<>();
l1.add(1);
l1.add(2);
l1.add(3);
l1.add(4);
l1.add(5);
l1.add(1,-1);
// 直接打印集合对象 "[1, -1, 2, 3, 4, 5]"
System.out.println(l1);
List<Integer> l2 = new ArrayList<>();
l2.add(-1);
l2.add(-2);
l2.add(-3);
l2.add(-4);
l2.add(-5);
l2.add(1,100);
l1.addAll(l2);
System.out.println(l1); // [1, -1, 2, 3, 4, 5, -1, 100, -2, -3, -4, -5]
// contains 是否包含"-3"数据
System.out.println(l1.contains(-3)); // true
// 获取指定位置的元素
System.out.println(l1.get(0)); // 1
// 查询某个元素所在的位置,若不存在返回-1
System.out.println(l1.indexOf(2)); // 2
// 删除某个元素
l1.remove((Object)100);
System.out.println(l1); // [1, -1, 2, 3, 4, 5, -1, -2, -3, -4, -5]
// 删除某个下标的元素
l1.remove(1);
System.out.println(l1); // [1, 2, 3, 4, 5, -1, -2, -3, -4, -5]
// 设置某个位置的数据
l1.set(0,200);
System.out.println(l1); // [200, 2, 3, 4, 5, -1, -2, -3, -4, -5]
// 长度
System.out.println(l1.size()); // 10
// 清空数据
l1.clear();
System.out.println(l1);
// 列表是否为空
System.out.println(l1.isEmpty()); // true
int[] arr = new int[]{1,2,3,4,5};
List<int[]> arr1 = List.of(arr); // 把arr当成一个元素存入arr1中
System.out.println(arr1.get(0)[0]); // 1
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
System.out.println(integers); // [1, 2, 3, 4, 5]
}
}
ArrayList内部结构是一个数组
- 如果初始化集合尽量指定初始化容量,如果确定不了,默认指定为16
- 使用泛型数据类型的时候,一定要使用引用数据类型
List集合中存放的数据
- 数据有顺序(添加的先后顺序)
- 数据可以重复
自己写一个转换工具类
public class ArrayConvertUtil {
public static Object[] toArrayConvert(List list) {
Object[] objects = new Object[list.size()];
for (int i = 0; i < list.size(); i++) {
objects[i] = list.get(i);
}
return objects;
}
public static List toListConvert(Object [] arr) {
List list = new ArrayList();
for (Object o : arr) {
list.add(o);
}
return list;
}
}
Collection的常用方法
返回值 | 方法 | 含义 |
---|---|---|
boolean | add | 添加单个元素 |
boolean | addAll | 添加多个元素 |
viod | clear | 清空 |
boolean | contains | 查找元素是否存在 |
boolean | containsAll | 查找多个元素是否都存在 |
boolean | equals | 比较此 collection 与指定对象是否相等。 |
boolean | isEmpty | 判断是否为空 |
boolean | remove | 删除指定元素 |
boolean | removeAll | 删除多个元素 |
Collection接口的遍历
使用Iterator
迭代器
Iterator
对象称为迭代器,主要用于编列Collection
集合中的元素
//得到当前集合的迭代器对象
Iterator<Object> iter = listname.iterator();
while(iter.hasNext){
Object outname = iter.next();
System.out.println(name);
}
List集合
List 接口下面主要有两个实现 ArrayList 和 LinkedList,他们都是有顺序的,也就是放进去
是什么顺序,取出来还是什么顺序,也就是基于线性存储,可以看作是一个可变数组
ArrayList:查询数据比较快,添加和删除数据比较慢(基于可变数组)
LinkedList:查询数据比较慢,添加和删除数据比较快(基于链表数据结构)
Vector:Vector 已经不建议使用,Vector 中的方法都是同步的,效率慢,已经被 ArrayList取代
Stack:是继承 Vector 实现了一个栈,栈结构是后进先出,目前已经被 LinkedList 取代
List的四种种遍历方式
使用Iterator
Iterator iter = col.iterator();
while(iter.hasNext()){
Object o = iter.next();
}
使用增强for
for(Object o : col){
}
使用普通for
for(int i = 0;i<list.size();i++){
Object object = list.get(i);
System.out.print(object);
}
Lambda表达式
lists.forEach(s -> {
System.out.println(s);
});
遍历存在的问题
- 迭代器遍历集合且直接用集合删除元素可能出现
- 增强for遍历集合且直接用集合删除元素可能出现
解决方案
- 用迭代器自身的remove去删除元素
- 使用普通for循环采取i– 或倒序删除
- 不能使用增强for循环删除集合中元素
Vector
Vector底层也是一个对象数组
Vector是线程同步的,即线程安全。Vector类的操作方法带有synchronized
在开发中,需要线程同步安全,考虑Vector
ArrayList与Vector比较
ArrayList:可变数组;不安全,效率高;如果有参构造1.5倍;如果无参:第一次10、第二次1.5倍扩
Vector:可变数组;安全效率不高;如果无参,默认是10;之后2倍扩容
LinkedList
- LinkedList实现了双向链表和双端队列特点
- 可以添加任意元素(元素可重复),包括null
- 线程不安全,没有实现同步
LinkedList底层原理
底层数据结构是双链表、查询慢、首尾操作的速度极快
LinkedList中维护两个属性first和last分别指向首节点和尾节点
Set接口
- 无序(添加与取出的顺序不一致,没有索引
- 不允许添加重复元素,最多只有一个null
注意:不能使用索引来获取对象,虽然是随机添加顺序,但取出的是固定的顺序
HashSet
HashSet底层是HashMap,HashMap底层是(数组+链表+红黑树)
LinkedHashSet
LinkedHashSet
是HashSet
的子类LinkedHashSet
底层是LinkedHashMap
,底层维护了一个数组+双向链表LinkedHashSet
根据元素的hashCode
值来决定元素的存储位置,同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的LinkedHashSet
不允许添加重复元素
LinkedHashSet底层机制
LinkedHashSet维护了一个hash表和双向链表
Map接口
- Map和Collection并列存在。
- Map中的key和value可以是任何引用类型的数据
- Map中的key不可以重复;value可以重复
- Map中的key和value可以为null;但key中只能有一个null
- 常用String类作为Map中的key
- key与value是一对一的关系
运用
public class MapMethod {
public static void main(String[] args) {
//演示map接口常用方法
Map map = new HashMap();
map.put("邓超", new Book("", 100));//OK
map.put("邓超", "孙俪");//替换-> 一会分析源码
map.put("王宝强", "马蓉");//OK
map.put("宋喆", "马蓉");//OK
map.put("刘令博", null);//OK
map.put(null, "刘亦菲");//OK
map.put("鹿晗", "关晓彤");//OK
map.put("hsp", "hsp的老婆");
System.out.println("map=" + map);
// remove:根据键删除映射关系
map.remove(null);
System.out.println("map=" + map);
// get:根据键获取值
Object val = map.get("鹿晗");
System.out.println("val=" + val);
// size:获取元素个数
System.out.println("k-v=" + map.size());
// isEmpty:判断个数是否为0
System.out.println(map.isEmpty());//F
// clear:清除k-v
//map.clear();
System.out.println("map=" + map);
// containsKey:查找键是否存在
System.out.println("结果=" + map.containsKey("hsp"));//T
}
}
class Book {
private String name;
private int num;
public Book(String name, int num) {
this.name = name;
this.num = num;
}
}
HashMap小结
- Map接口的常用实现类:HashMap、Hashtable、Properties
- HashMap是Map接口中使用频率最高的实现类
- HasMap是以key-val对的方式存储数据
- key不能重复,但是值可以重复,允许使用null键和null值
- 如果添加相同的key,则会覆盖原来的key-val,等同于修改
- 和HashSet一样,不保证映射的顺序,因为底层是以hash表的方式存储的
- HashMap没有实现同步,因此是线程不安全的,方法没有做同步互斥的操作
Hashtable的基本介绍
- 存放键值对K-V
- Hashtable的键值都不能为null,否则会抛异常
- Hashtable使用的方法基本和HashMap方法一样
- Hashtable是线程安全的,HashMap是线程不安全的
- 与HashMap比效率较低
Collections工具类
Collections是一个操作Set、List、Map等集合的工具类
基础运用
public class Collections_ {
public static void main(String[] args) {
//创建ArrayList 集合,用于测试.
List list = new ArrayList();
list.add("tom");
list.add("smith");
list.add("king");
list.add("milan");
list.add("tom");
// reverse(List):反转 List 中元素的顺序
Collections.reverse(list);
System.out.println("list=" + list);
// shuffle(List):对 List 集合元素进行随机排序
// for (int i = 0; i < 5; i++) {
// Collections.shuffle(list);
// System.out.println("list=" + list);
// }
// sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
Collections.sort(list);
System.out.println("自然排序后");
System.out.println("list=" + list);
// sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
//我们希望按照 字符串的长度大小排序
Collections.sort(list, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
//可以加入校验代码.
return ((String) o2).length() - ((String) o1).length();//List允许重复,所以能同时有两个长度相同的
}
});
System.out.println("字符串长度大小排序=" + list);
// swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
//比如
Collections.swap(list, 0, 1);
System.out.println("交换后的情况");
System.out.println("list=" + list);
//Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
System.out.println("自然顺序最大元素=" + Collections.max(list));
//Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素
//比如,我们要返回长度最大的元素
Object maxObject = Collections.max(list, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((String)o1).length() - ((String)o2).length();
}
});
System.out.println("长度最大的元素=" + maxObject);
//Object min(Collection)
//Object min(Collection,Comparator)
//上面的两个方法,参考max即可
//int frequency(Collection,Object):返回指定集合中指定元素的出现次数
System.out.println("tom出现的次数=" + Collections.frequency(list, "tom"));
//void copy(List dest,List src):将src中的内容复制到dest中
ArrayList dest = new ArrayList();
//为了完成一个完整拷贝,我们需要先给dest 赋值,大小和list.size()一样
for(int i = 0; i < list.size(); i++) {
dest.add("");
}
//注意:size是指元素个数,而length是数组长度,构造器是不会改变size的。不能通过初始化集合来给定大小,因为这并不会改变size,底层是用两个集合的size比较的,size 和 length 不能等同,size 表示 当前集合的元素个数, 随着元素的增加而增加。
//拷贝
Collections.copy(dest, list);
System.out.println("dest=" + dest);
//boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值
//如果list中,有tom 就替换成 汤姆
Collections.replaceAll(list, "tom", "汤姆");
System.out.println("list替换后=" + list);
}
}
时间变得如此宝贵,坐下来休息是件不堪设想的事情。只要朝着某个方向去,或朝任何方向走,就多少会有进展,说不定就会有好结果,否则就是坐以待毙,就是缩短死神赶上他们的时间。 ——马克·吐温《汤姆·索亚历险记》
5 条评论
123
Test
llll