集合
定义
集合:装数据的容器
两种实现接口:List和Set
Collection接口
包含List接口与Set接口
List接口
ArrayList
- 底层是一个数组实现的
- 长度不限制,可以自动扩容
默认初始容量为0,加一个元素扩容到10,加载因子为1,扩容1.5倍 - 若有设置的初始容量使用设置的初始容量
- 是有序的,可以通过索引操作
- 存放的内容可以重复
- 线程不安全,效率高
List<String> list = new ArrayList<String>();
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
list.add("zhaoliu");
list.add("tianqi");
list.clear();//清除集合元素
list.add(0, "hello");//第0个位置加入元素
System.out.println(list.isEmpty());//判断数组是否为空
System.out.println(list.get(2));//查找位置2的元素
System.out.println(list.indexOf("tianqi"));//查找某元素的位置
System.out.println(list.lastIndexOf("hello"));//查找某元素最后出现的位置
list.remove(0);//删除第0个元素
list.remove("tianqi");//删除
list.set(1, "heyi");//第一个位置替换元素
Object [] array = list.toArray();//将数据存放到数组
System.out.println(Arrays.toString(array));
for(String name : list){
System.out.println(name);
}//查询所有元素
for(int i=list.size()-1;i>=0;i--){
list.remove(list.size()-1);
}//一个一个删除元素
Vector
线程安全的,效率低
List<String> v = new Vector<String>();
v.add("aa");// 添加元素
LinkedList
底层结构是一个链表,用法跟ArrayList相似
Set接口
- 存放元素是无序的
- 底层是HashMap,用于保存数据。实现Set接口
- 遍历需要用到迭代器Iterator,foreach 底层就是用迭代器实现的,迭代器是快速失败的
- 使用方法与arraylist相近
HashSet
初始容量是16(2的n次方),加载因子0.75,扩容2倍。若有设置初始容量,则使用大于此初始容量的2的幂。
Set<String> set = new HashSet<String>();
set.add("zhangsan");
set.add("lisi");
set.add("wangwu");
set.add("zhaoliu");
set.clear();
System.out.println(set.contains("lisi"));
System.out.println(set.hashCode());//哈希码值// System.out.println(set.isEmpty());
System.out.println(set.remove("zhaoliu"));
System.out.println(set.size());
System.out.println(set.equals("lisi"));
System.out.println(Arrays.toString(set.toArray()));
Iterator<String> iterator = set.iterator();//迭代器
while(iterator.hasNext()){ //hasNext()探查,当查到前一步有值,返回true
String s = iterator.next(); //next():当探查为true则向前一步
System.out.println(s);//next保证只调用一次
System.out.println(s);
System.out.println(s);
}
TreeSet
- 底层结构是TreeMap (红黑树–2叉树中的一种)
- TreeSet线程不安全,性能不如HashSet
- 但是有序(String自然顺序,不是插入顺序),不可重复
- 插入元素如果为非基本类型则需要用比较器设置比较方式(Comparable)
Set<Person> s = new TreeSet<Person>();
s.add(new Person("seven01","男",18));
s.add(new Person("seven01","男",19));
s.add(new Person("seven01","男",28));
s.add(new Person("seven01","男",38));
// s.add(null);不能存一个null的key
for (Person person : s) {
System.out.println(person);
}
迭代器Iterator
迭代器是快速失败的,必须保证expectedModCount = modCount
,不满足此情况就会报异常
// 初始化一个集合,添加一些测试数据
Set<String> set = new HashSet<String>();
set.add("chenyulin");
set.add("liangteng");
set.add("lizhengwang");
set.add("zhanghuan");
set.add("tangrenjie");
// set.remove("liangteng");
// 1,hasNext 跟next 调用1对1
Iterator<String> iterator = set.iterator(); //java.util.HashMap$KeyIterator
System.out.println(iterator);
while(iterator.hasNext()){
String s = iterator.next();// next保证只调用一次
// set.remove(s);// 迭代的时候不能通过集合来删除或者添加元素。
if("zhanghuan".equals(s)){
iterator.remove(); // 可以通过迭代器来删除
}
}
// 遍历所有数据
for (String string : set) {
System.out.println(string);
}
Map接口
- Map用来存两个字段:键和值
- Map的key是不能重复的。如果重复后面覆盖前面的。
@Test
public void testHashMap(){
Map<String,String> m = new HashMap<String,String>() ;
m.put("name", "seven");// 添加2个字段
m.put("age", "18");
m.put("sex", "男");
m.put("sex", "女");// 覆盖上一行
System.out.println(m.containsKey("sex"));// 检查是否有这个键
System.out.println(m.containsValue("18"));// 检查是否有这个值
System.out.println(m.get("sex"));// 根据key获取值
System.out.println(m.isEmpty());//
// m.remove("age");删除key对应的数据
System.out.println(m.size());// 集合键值对数量
Collection<String> values = m.values();//把所有的value拿出来放入collection集合中
for (String string : values) {
System.out.println(string);
}
Set<String> keySet = m.keySet();//把所有的key拿出来放入Set集合中
for (String string : keySet) {
System.out.println(string);
}
Set<Entry<String, String>> entrySet = m.entrySet();
for (Entry<String, String> entry : entrySet) {
System.out.println(entry.getKey() + " --- "+entry.getValue());
}//同时查询键值对
}
HashMap
- hashcode在hash开头的集合里面,(HashMap HashSet HashTable),通过hash值来决定元素存放顺序
- 默认初始容量是16(2的n次方) 加载因子0.75,扩容2倍
- 若有设置初始容量,则使用大于此初始容量的最小2的幂。
- 线程不安全,效率高
- 支持key跟value为null,只有一个key为null,值可以多个NULL
底层结构
(1.8)底层结构是 数组+链表+红黑树
- hash冲突(hash碰撞):不同的关键码 经过hash算法以后得到了相同值。
- 首先把Key经过hashcode和hash得到一个整数值。
- 将这个整数值跟数组table的长度取余数。这个余数就是存的数组的索引。
- 如果2个Key得到的索引相同(有2个元素存在同一个桶里面),先通过equals进行判断,如果为true表示是相同(逻辑上)的对象,那么就进行覆盖。如果equals返回时的false,表示是不同的元素,只是发生了hash冲突,那么就以链表的形式接在后面。
- 当一个链表的长度达到了8,并且数组的长度达到了64,会把链表结构转成红黑树。如果没有达到64则把数组扩容。
- 当一个红黑树元素当减少到6个时候结构再转换成链表。
ConcurrentHashMap
它是线程安全的,用法跟hashmap一样,只是将数据分割成多段(16),分别给不同的段上锁。
HashTable
- 默认初始容量为11,加载因子为0.75 扩容2倍+1
- 线程安全,效率低
- 若有设置初始容量,则使用此值
- 不支持key跟value为null
TreeMap
- 底层结构是红黑树(2叉树中的一种)
- TreeMap线程不安全, 有序(String自然顺序(定制顺序),不是插入顺序)
- 插入元素如果为非基本类型则需要可比性(Comparable)
- key不能为null,值可以为null