单列集合Collection
Collection是单列集合的顶层接口,所有方法被List和Set系列集合共享
List:添加元素是有序的、可重复、有索引
Set:添加元素是无序的、不重复、无索引
- 常见成员方法:
add clear remove contains isEmpty size - 三种通用的遍历方式
- 迭代器:在遍历的过程中需要删除元素时使用
- 增强for
- Lambda: 仅仅想遍历,使用后两种
- Collection迭代器遍历:
-
迭代器在遍历集合的时候不依赖索引
-
迭代器需要掌握三个方法
-
迭代器的四个细节:
- 如果当前位置没有元素,还要强行获取,会报NoSuchElementException
- 迭代器遍历完毕,指针不会复位
- 循环中只能用一次next方法
- 迭代器遍历时,不能用结合的方法进行增加或删除
-
List
- List对象创建
List是一个接口,需要通过实现子类创建对象。List中存放的类型只能是Object及其子类,所以不能存放int, 应该为Integer
List<Integer> list1 = new ArrayList<>();//然后通过add()添加元素
List<Integer> list2 = new LinkedList<>();
- List方法
//增删改查
add(Object data);//末尾增加data
add(Object data, pos);//在位置pos增加data
remove(int pos);//删除指定位置的元素
remove(Object);//删除指定元素
set(Object, pos);//修改指定位置的元素
forEach();//for循环遍历
iterator();//迭代器遍历
Set
- 无序、不重复、无索引
- Set集合的方法基本上与Collection的API一致
- Hash Set:无序、不重复、无索引
- LinkedHashSet:有序、不重复、无索引
- TreeSet:可排序、不重复、无索引
双列集合Map
Map是一个接口
-
特点
- 双列集合一次需要存一对数据,分别为键和值(例如商品和价格)
- 键不能重复,值可以重复
- 键和值是意义对应的,每个键只能找到自己对应的值
- 键+值这个整体称为”键值对“或”键值对对象“,Java中叫做”Entry对象“
-
方法
-
基本方法
Map<K, V> m = new HashMap();//K、V为键值的类型 //添加数据,若键已存在,会把原有的键值对覆盖,并返回被覆盖的值 //若键不存在,返回null m.put(K key,V value); //删除指定键值对并返回该值 m.remove(Object key); //清空 void clear(); // boolean containsKey(Object key); // boolean containsValue(Object Value); // boolean isEmpty(); // int size(); //输出 System.out.println(m);
-
entrySet();
返回的是键值对对象
-
-
遍历
-
用keySet()方法获取所有键,返回的是Set集合,再通过get(key)方法获得key对应的值。(键找值)
//增强for遍历 Set<K> keys = map.keySet(); for(K key : keys){ V value = map.get(key); } //Lambda表达式遍历 keys.forEach(key -> System.out.println(key)); //迭代器遍历 Iterator<K> it = keys.iterator(); while(it.hasNext()){ System.out.println(it.next()); }
-
entry对遍历
Set<Map.Entry<K,V>> entries = map.entrySet(); for(Map.Entry<K, V> entry : entries){ K key = entry.getKey(); V value = entry.getValue(); } // entries.forEach(entry -> System.out.println(entry)); // Iterator<Map.Entry<K, V>> it2 = entries.iterator(); while(it2.hasNext()){ System.out.println(it2.next()); }
-
map遍历(Lambda)
方法:default void forEach(Biconsumer<? super K,? super V> action)System.out.println("Map遍历:"); map.forEach(new BiConsumer<K, V>() { @Override public void accept(K key, V value) { System.out.println(key + "=" + value); } }); System.out.println("Map遍历(+lambda表达式):"); map.forEach(( key, value) -> System.out.println(key + "=" + value));
-
HashMap
-
特点
- HashMap是Map的一个实现类,没有额外需要学习的特有方法,直接用Map里的方法。
- 特点都是由键决定的:无序、不重复、无索引
- 和HashSet的底层原理一模一样,都是哈希表结构(数组加链表)
-
底层原理
添加元素时,根据元素的哈希值确定存入位置,
若数组位置为null(该位置没有元素),则直接存入;
若数组位置不为null,且键不重复,则挂在下面形成链表或红黑树(链表长度大于64时形成红黑树),如果链表的元素和添加元素的哈希值和键重复了(两个都判断是为了防止哈希碰撞),则修改最后链表已有元素的值,进行元素覆盖(而不是直接用添加元素直接替换已有元素)
若存入的元素为基础类型(String也算),则直接拷贝;若不是基础类型,则存入地址,一律占8字节。若创建红黑树,不需要实现Compareable接口或传递比较器对象,因为默认用哈希值的大小来创建红黑树。
LinkedHashMap
- 特点:
- 由键决定:有序、不重复、无索引,有序指的是保证存储和取出的元素顺序一致。
- 原理:底层数据结构是哈希表,只是每个键值对元素又额外多了一个双链表的机制记录存储的顺序。
Hashtable
Properties
TreeMap
- 特点
- 底层原理:红黑树(和TreeSet一样),所以增删改查性能较好
- 由键决定:可排序、不重复、无索引
- 默认按照键的顺序,从小到大排序,也可以按自己规定的规则排序
代码书写两种排序规则:1. 实现Comparable接口,指定比较规则(当key是自定义对象时,需要让类继承该接口,并重写compareTo方法,以此来指定比较规则);2. 创建集合时传递Comparator比较器对象,指定比较规则。若两种规则都写了,以第二种为准。 - HashMap不排序,效率比TreeMap更高。
以key从大到小的顺序排列:
TreeMap<Integer, String> tm = new TreeMap<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2- o1;
}
});
Compareable接口,以学生的年龄递增为顺序,年龄相等则按照名字的顺序
(继承接口后有红色波浪线,选中并按alt+回车,选则implements methods,可以选择要重写的方法)
public class Student implements Comparable<Student>{
private int age;
private String name;
//JavaBean省略
@Override
public int compareTo(Student o) {
//o: 已经在红黑树中存在的元素
//this: 新添加的元素
int i = this.getAge() - o.getAge();
i = i == 0 ? this.getName().compareTo(o.getName()) : i;
//这一行的compareTo()是String的方法
return i;
}
}
- 底层原理
三种双链集合如何选择:
默认:HashMap(效率最高,仅管最坏情况(所有元素都在一个数组位置形成了链表)时效率低,但这样的情况极少),操作复杂度O(1)
保证存取有序:LinkedHashMap
需要排序:TreeMap,操作复杂度O(logN) - API
集合工具类Collections
常用API
调用方法时可以直接用类名调用:Collections.addAll();
其他
- JDK5以后,方法的形参可以是可变参数,即形参的个数可以发生变化,格式:
方法名(属性类型…形参名)
注意:- 但可变参数在一个方法的形参中最多只能有一个
- 可变参数要写在其他参数的后面,写在最后
- 可变参数本质是一个数组
例子:求和方法
public static int getSum(int...a){
int sum = 0;
for (int i = 0; i < a.length; i++) {
sum += a[i];
}
return sum;
}
不可变集合
集合一旦生成,无法删改,只能查询
- 创建
//List List<String> list = List.of("aa","bb","cc","dd"); //Set: 元素不能重复 Set<String> set = Set.of("aaa","bbb","ccc"); //Map 最多只能添加10个键值对 Map<String,String> map1 = Map.of("aaa","111","bbb","222","ccc","333"); //Map.copyOf():直接传入Map集合, // 若已经是不可变集合则直接返回输入,若是可变集合则转换为不可变集合 Map<String,String> hm = new HashMap<>(); hm.put("aaa","111"); hm.put("bbb","222"); hm.put("ccc","333"); Map<String,String> map2 = Map.copyOf(hm);
Map.of()最多只能传递10个键值对,因为它的输入形参不是可变参数,是10个键值对。因为形参最多只能有一个可变参数。如果要传递大于10个键值对,要用Map.ofEntries(),它的形参是可变参数,所以传递的是数组,要把entries转换为数组(使用entries.toArray()方法)。JDK10开始,可以直接使用Map.copyOf()将可变Map集合转换为不可变集合。