集合/容器
数组特点:
一组数据类型相同的元素集合
创建数组时,必须给定长度,而且一旦创建,长度不能改变
一旦数组装满元素,就需要创建一个新的数组把原来的元素复制过去
不方便;
判断是否装满,如果装满了,数组复制创建一个新的元素
如果我们从数组中间删除一个元素,或者添加一个元素,需要移动后面的元素
java中为了解决数据存储单一的情况,java中提供了许多不同结构的集合类,让我们可以根据不同的场景进行数据的存储和选择,集合中的长度都是可变的
提供了数组实现的集合,链表实现的集合,哈希结构,树结构
集合
单列集合
一次放进去一个值,或一个对象
Collection接口,定义了单列集合共有的方法
List:可以有重复元素
ArrayList:数组列表
数据采用数组方式储存
底层有一个数字,可以动态的拓展数组的长度,并提供一系列的方法操作
集合容器类中默认可以添加Object类型
但是一般还是习惯一个集合对象中保存同一种类型
泛型:可以在声明类型时,自定义参数类型
ArrayList
add(E e)默认是向末尾添加元素
add(0,“e”)向指定维持添加元素
remove(“d”),匹配删除第一个指定的元素,删除成功返回true,否则返回false
remove(1),删除指定位置的元素,删除成功并返回所删除的元素
get(1),获取指定位置的元素
indexOf,获取指定元素第一次出现的位置,lastindexOf,从最后一位开始获取指定元素第一次出现的位置
set(1,“x”),替换并返回指定位置上的元素
isEmpty,判断集合中的元素是否为空
clear,清空集合中所有的元素
contains("c")判断是否包含指定的元素
size()返回集合中元素的个数
LinkedList:链表列表
底层是一个链表类,查询速度慢
add(“d”)向链表的末尾添加元素
add(1,“d”)向链表指定的位置插入元素
get(1)获取指定位置的元素
remove(“d”)删除指定的元素
remove(1)删除指定位置的元素
remove()删除并返回第一个元素
removeFirst()删除并返回第一个元素
addFirst()从头开始添加元素
removeLast(),addLast()队列 先进先出 栈 后进后出
Vector:数组列表 线程安全
List接口集合迭代
for循环遍历
for (int i=0;i<arrayList.size();i++){
System.out.println(arrayList.get(i));
}
允许对元素进行修改,但要注意修改完后元素的索引会改变,导致所修改的判断位置产生偏移
增强for循环的遍历
for (String s:arrayList){
System.out.println(s);
}
}
不能在遍历的时候修改集合元素(删除,添加)
迭代器遍历(Iterator)
Iterator<String> it = arrayList.iterator();
while (it.hasNext()){
String s = it.next();
if(s.equals("a")){
it.remove();
}
}
通过迭代器可以实现遍历数组并删除指定的元素
ListIterator迭代器,只能对List接口下的实现类遍历
可以实现从后向前遍历
$$
Set接口:
Set接口继承了Collection接口,Set中存储的元素不能有重复元素,Set中的元素是无索引的
HashSet
HashSet类中的元素不能重复,且元素是无序的,通过HashCode和equals方法判断元素是否重复
HashSet<String> set = new HashSet<>();
set.add("2");
set.add("5");
set.add("333");
set.add("66");
set.add("1");
System.out.println(set);
//输出结果为[66, 1, 2, 333, 5]
HashSet在添加元素时是如何判断元素重复的:
当我们向集合中添加一个元素时,如歌每次都使用equals()比较内容是否相等效率会很低
所以HashSet中在底层会调用hashCode()–Object中的hashCode()返回的是对象的地址(不调用这个),会调用类中重写的hashCode(),返回的是根据内容计算的哈希值
遍历时会用哈希值先比较是否相等,会提高比较的效率
但是哈希值会存在问题,出现内容不同哈希值相同的情况,此种情况下再调用equals方法来判断内容是否相等,
TreeSet
可以给Set集合中的元素进行指定方式的排序(有序),存储的对象必须实现Comparable接口
TreeSet<Integer>treeSet = new TreeSet<Integer>();
treeSet.add(1);
treeSet.add(5);
treeSet.add(3);
treeSet.add(1);
//储存结果为1,3,5,没有重复元素1,经过了排序
底层使用了树形结构,树结构本身就是有序的
向treeset中添加的元素类型必须实现compareable接口,重写compareTo方法,每一次添加元素时,调用compareTo方法来进行元素大小的判断(<0放左子节点,=0表示重复,>0放在右子节点)
双列集合
键值映射
Map(Mapping)
数据存储是键:值的形式储存
键不能重复,值可以重复
通过键可以找到值
一个键只能映射到一个值
HashMap
键是无序的
map中添加的键如果重复则替换之前的键
HashMap底层存储数据结构
哈希表(数组),链表,树(红黑树)
第一步:用key计算哈希值,
1,数组主要用于定位 key–计算出一个int的哈希值 hash%数组长度(hash数组的默认长度是16),将元素放在哈希表中指定的位置
2,继续添加元素时,如果出现相同位置且不重复的元素,那么将后来的元素添加到之前元素的next节点位置
3,当链表的长度>=8时,且哈希数组长度>=64,链表会自动转为红黑树
4,哈希表负载因子为0.75,当哈希表使用数组的0.75时,会自动扩容为原来数组长度的2倍
TreeMap
底层使用树形结构存储键值
TreeMap
键可以排序
键元素的类型必须实现comaprable接口,重写compareTo方法
TreeMap<Integer, String> treeMap = new TreeMap<>();
treeMap.put(2,"aa");
treeMap.put(3,"baa");
treeMap.put(5,"caaa");
treeMap.put(4,"daaaa");
treeMap.put(6,"eaaaaa");
System.out.println(treeMap);
Hashtable
底层实现也是用到key的哈希值,计算位置,判断元素是否重复
方法上都添加了synchronized锁
Hashtable中不能储存为null的键和为null的锁,null无法调用Hashcode方法
HashMap可以储存一个为null的键,值可以为null
Map集合遍历
方式1:先拿到所有的键,再遍历键,根据键找值
map.keySet()拿到所有的键
Set<String> keyset = treeMap.keySet();
for (String key:keyset){
System.out.println(key+":"+treeMap.get(key));
方式2:
Set<Map.Entry<String,String>> entries = treeMap.entrySet();
for (Map.Entry entry:entries){
System.out.println(entry.getKey()+":"+entry.getValue());
Collections类
addAll,将指定的可变长度参数数据添加到指定的集合中
addAll(Collection<? super T> c, T… elements)
int...a 可变长度的参数,本质是一个数组
一个参数列表中只能有一个可变长度参数,必须放在参数列表的最后
//自定义排序规则
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
Collections.sort(list, new Comparator<Integer>() {//创建了一个实现comparator接口的匿名内部类对象,省去创建一个类,简化语法
@Override
public int compare(Integer o1, Integer o2) {
return o1.intValue()-o2.intValue();//降序
}}
);
System.out.println(Collections.binarySearch(list,13));
//binarysearch二分查找法,在sort后进行查找,查找为升序
swap(List<?>list ,int i,int j)交换i和j
copy(list1,list);集合复制,将原集合复制到目标集合 要求目标集合size大于等于原集合的size
Colllections.shuffle(List<?> list)随机排序,将数组中的元素随机排序
reverse(list)逆序