java之集合
一、简介
数组可以储存对象,也可以存储基本数据类型 Person[]
集合中不可以存放基本数据类型
Collection :泛型
通过泛型来设定里面可以存放哪些内容
泛型的类型必须是引用数据类型
集合:储存数据的容器。Collection是集合的顶级接口。里面不可以存放基本数据类型。
二、List
特点:有序集合。存储和取出的顺序是一致的
存在索引
允许存在重复的元素
1.ArrayList
List接口的实现类-- ArrayList(顺序表)
底层的数据结构是一个数组,可以自动扩容
ArrayList扩容:初始容量默认是10
扩容是每次增加原有容量的一半
10 --> 15 --> 22
源码如下
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
ArrayList,增删比较慢 查询速度快
线程不安全的一个列表
2.LinkedList(链表)
链表的特点:增删快 查询慢 线程不安全
如果数据决定了查询和增删效率差不多,那么优先选择ArrayList还是LinkedList??
选择LinkedList
因为LinkedList是内存不连续的。ArrayList是内存连续的。
三、迭代器
Enumeration 是JDK1.0出现。现在不常用。被iterator替代。
Collention接口的父接口是Iterable,增强for循环本质上就是迭代器。
It.remove(迭代器的删除方法):
迭代器在迭代的过程中,会复制一份新的集合出来。然后在新的集合中迭代,并且根据删除状态添加对应的标记。最后迭代完成之后,需要集合合并,会检查对应的标记决定是否执行删除操作。
如果是集合(list.remove())的删除方法:在原有集合上面直接删除。添加同理
注意:添加,删除都不行,会 报错。
增强for循环能够一边循环一边删除吗?
不能
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("efef");
list.add("rtr");
list.add("hght");
list.add("vbbg");
// 获取迭代器
Iterator<String> it = list.iterator();
// 循环迭代
while (it.hasNext()){//list.remove和it.remove 都是先把数组复制一遍 执行完再比对
String s = it.next();
list.remove(s); //在原数组操作,然后比对 会报错
// it.remove(); //在复制后数组操作,然后比对
// System.out.println(s);
}
System.out.println(list);
}
三、Set(散列集合)
Set特点:存放的元素不能重复
1.HashSet
HashSet:底层是使用HashMap数据结构
是无序的
不保证数据的位置(数据位置是可能发生改变的)
线程不安全
默认的初始容量是16
HashSet指定初始容量,底层会保证结果一定是2的n次方的形式
10–>16 17 -->32
2.LinkedHashSet
LinkedHashSet:是有序的集合(用的很少)
为什么是一个有序的集合?
每一个桶之间的链表也有联系
默认加载因子(0.75f),假设有16个桶,一个桶中存放10000个数据,其他桶中没有数据,那么会不会扩容??
不会扩容。因为实际使用的桶数量 1 / 16 < 0.75f
在JDK1.8之前,没有办法。在JDK1.8之后(链表长度超过8之后)会将桶中的链式栈结构扭转为二叉树结构,从而提升效率。
四、Stream(流)
操作集合的流式结构。
里面提供了大量的操作集合的好用的方法。
stream的方法,大部分都是传入接口,而且接口中只有一个抽象方法,那么可以考虑使用JDK1.8的特性 Lamda表达式
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class StreamDemo {
public static void main(String[] args) {
// 创建列表
List<String> list = new ArrayList<String>();
list.add("C1");
list.add("hyth");
list.add("qerki");
list.add("c2");
list.add("ctr");
list.add("yujhg");
// 获取流对象
Stream<String> stream = list.stream();
// 先过滤掉首字符不是c的内容
// 转换为大写
// 比较排序
// 输出
stream.filter(str -> str.startsWith("c")).
map(str -> str.toUpperCase()).
sorted((s1,s2) -> s1.compareTo(s2)).
forEach(str -> System.out.println(str));
// 排序
// stream.sorted(new Comparator<String>() {
//
// @Override
// public int compare(String o1, String o2) {
// // TODO Auto-generated method stub
// return o1.compareTo(o2);
// }
// });
// 过滤方法
// stream.filter(new Predicate<String>() {
//
// @Override
// public boolean test(String t) {
// // TODO Auto-generated method stub
// return t.startsWith("C");
// }
// }).forEach(new Consumer<String>() {
//
// @Override
// public void accept(String t) {
// // TODO Auto-generated method stub
// System.out.println(t);
// }
// });
System.out.println(list);
}
}
五、泛型
泛型是JDK1.5之后的特性。
来保证程序的安全性
泛型限定了集合中的数据类型,保证了程序的安全性
泛型在JDK1.7之后,new后面的泛型可以省略成一个<>
ArrayList list = new ArrayList<>();
泛型的规则: <大写字母A> A:代表传入的实际数据类型
T: Type
E: Element
K: key
V: value
在类中使用泛型: 在类名后加上<大写字母>
如果类中有多个泛型,需要使用,隔开 <T,K>
接口使用泛型分为两种情况
1、接口中是声明泛型,实现类也声明泛型,那么需要在实现类后面,并且在实现类的接口后面加
2、接口的实现类泛型确定
方法中的泛型
在方法的返回值前添加<大写字母>,在参数列表和方法体中就可以使用