一、集合介绍
1、介绍
集合又称容器,是Java中对数据结构(数据存储方式)的具体实现。
我们可以利用集合存放数据,也可以对集合进行新增、删除、修改、查看等操作。
集合数据都是在内存中,当程序关闭或重启后集合中数据会丢失,所以集合是一种临时存储数据的容器。
2、JDK中集合结构图
集合作为一个容器,可以存储多个元素,但是由于数据结构的不同,Java提供了多种集合类,将集合类中共性的功能,不断向上抽取,最终形成了集合体系结构。
2.1 List 接口和 Set 接口
1、 List 接口:存储有序(插入顺序),可重复数据
- Vector: List 的实现类,底层为可变长度数据实现。所有方法都是同步操作(线程安全),每次扩容成本增长。新数组长度为原数组长度的2倍。
- ArrayList:List 实现类,底层为可变长度数组实现。所有方法都是非同步操作(非线程安全的),以1.5倍的方式在扩容。常用于:较多查询的情况。
- LinkedList:List的实现类,双向非循环链表的实现。常用于:删、增较多的情况。
总结
ArrayList 和 Vector比较:
相同点:
底层都是可变长数组实现,存储的元素有序可重复
不同点:
ArrayList 扩容后为之前长度的 1.5倍,非同步操作(线程不安全),性能更好
Vector扩容后为之前长度的 2 倍,同步操作(线程安全),性能差
ArrayList 和 LinkedList:
相同点:
存储的元素有序可重复,都是非同步操作(线程不安全)
不同点:
底层实现不同,ArrayList 数组实现,LinkedList 双向链表实现
2、Set 接口:存储无序,不可重复数据
- HashSet:Set 实现类,底层是 HashMap 散列表(数组 + 链表 + 红黑树 jdk1.8及之后)。所有添加到 HashSet 中的元素实际存储到了 HashMap 的 key中。
- LinkedHashSet:HashSet 子类,使用 LinkedHashMap 来存储它的元素,存储的值插入到 LinkedHashMap 的可以 key中,底层实现(数组 + 链表 + (红黑树 jdk1.8及之后)+ 链表),可以记录插入的顺序
- TreeSet:Set 实现类,底层是 TreeMap(红黑树实现),存入到 TreeSet 中的元素,实际存储到了 TreeMap 中,根据存储元素的大小可以进行排序。
总结:
ArrayList 和 HashSet
不同点:ArrayList 存储的数据有序有下标,元素可以重复(底层原因,使用的是数组),可以根据下标获取,HashSet 存储的元素没有下标,没有顺序,元素不可以重复(底层原因,使用 HashMap 存储 数组 + 链表 + (红黑树jdk1.8)之后)
LinkedHashSet 和 TreeSet
相同点:有顺序
不同点:LinkedHashSet 底层 LinkedHashMap 保证插入的顺序
TreeSet 底层 TreeMap(红黑树)保证 key 值大小的顺序。
2.2 Map 接口
Map:独立的接口。每个元素都包含key(名称)和 value(要存储的值)两个值。
- HashMap:Map 实现类,对散列表(数组+链表+(红黑树 jdk1.8及之后))的具体实现,非同步操作(非线程安全的)。存储时以Entry 类型存储(key, value)
- LinkedHashMap:HashMap 的子类,是基于 HashMap 和链表来实现的。在 HashMap 存储结构值上再添加链表,链表只是为了保证顺序
- TreeMap:Map 实现类,使用的不是散列表,而是对红黑树的具体实现。根据 key 值的大小,放入红黑树中,可实现排序的功能(key 值大小排序)
- HashTable:Map 实现类,和 HashMap 数据结构一样,采用散列表(数组 + 链表 + (红黑树 jdk1.8及之后))的方法实现,对外提供的 public 函数几乎都是同步的 (线程安全)。
总结:
HashMap 和 HashTable
相同点:
存储的数据结构一样,插入的数据无序
不同点:
- HashMap 非同步操作(线程不安全),HashTable 同步操作(线程安全)
- HashMap 允许只能有一个 key 为 null 值,因为 hashmap 如果 key 值相同,新的 value 将替代旧的。HashTable 不允许 null 值
LinkedHashMap 和 TreeMap
相同点:有顺序
不同点:
- 底层实现不同
- LinkedHashMap 通过(数组 + 链表 + (红黑树 jdk1.8 及之后))和 链表保证插入的顺序,TreeMap 通过红黑树保证 key 值大小的顺序
常用的集合:ArrayList,HashMap,HashSet
Collection 接口
1、接口
List 和 Set 接口的父接口,还有其他的实现类或子接口。
2、继承关系
3、包含的API
泛型中<? extends E> 代表:只要 E 类型或 E 类型的子类都可以
三、List接口
1、介绍
Collection 接口的子接口。Collection 中包含的内容 List 接口中可以继承。
List 专门存储有序,可重复数据的接口
2、包含的 API
四、ArrayList
1、介绍
实现了List接口,实现底层数组扩容
存储有序、可重复数组,有下标
2、实例化
常用向上转型进行实例化。绝大多数集合都支持泛型,如果不写泛型认为泛型是,使用集合时建议一定要指定泛型。
List<泛型类型> 对象 = new ArrayList<>()
3、内存结构图
4、常用 API
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;public class TestArrayList {/** ArrayList 的基本使用:* ArrayList 自身可以动态调整大小* ArrayList 的内部使用数组存储元素,当数组将被存满,就会创建一个新数组,其容量是当前数组的 1.5 倍* 同时,所有元素都将移至新数组,假设内部数组已满,而我们现在又添加了一个元素,ArrayList 容量就会以相同* 的比例扩展(在这种情况下,内部数组中将有一些未分配的空间)。此时,trimToSize()方法可以删除未分配的空间* 并更改 ArrayList 的容量,使其等于 ArrayList 中的元素个数* */public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();//1.增加元素list.add("Tom");list.add("Marry");list.add("Andy");list.add("Jhon");System.out.println(list);//2.访问元素/*System.out.println(list.get(1));*/ // 通过元素下标访问第二个元素//3.修改元素/* list.set(1, "ZS");System.out.println(list);*///4.删除元素/*list.remove(1);System.out.println(list);*///5.计算大小/*int length = list.size();System.out.println(length);*///6、迭代数组列表/*for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}*///7.使用for-each 来迭代元素/*for (String s : list) {System.out.println(s);}*///8.ArrayList 排序//8.1 使用 Arrays 自带方法 sort//正序/*list.sort(Comparator.naturalOrder());System.out.println(list);//倒序list.sort(Comparator.reverseOrder());System.out.println(list);*///9.插入元素到指定为止/*list.add(2, "Pm");System.out.println(list.toString());*///10.添加集合中所有元素到 arrayList 中/*ArrayList<String> list1 = new ArrayList<String>();list1.add("GOD");list1.add("SD");//把 list1 所有元素添加到 list 中list.addAll(list1);// 在指定位置插入 list1list.addAll(2, list1);System.out.println(list);*///11.删除 arrayList 中所有的元素//list.clear();/*list.removeAll(list);System.out.println("所有 clear() 方法后: " + list);*///12.赋值一份 arrayList//clone 属于浅拷贝,浅拷贝只是赋值指向某个对象的指针,而不复制对象本身,新旧对象还是共享一块内存,// 所以如果期中一个对象改变了这个地址,就会影响到另一个对象//浅拷贝对应的就是深拷贝,深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,//且修改新对象不会影响原对象/*ArrayList<String> cloneList = (ArrayList<String>)list.clone();System.out.println("拷贝 ArrayList:" + cloneList);*///13.判断元素是否存在于 arrayList 中/*System.out.println("Marry 是否存在于 arrayList中");System.out.println(list.contains("Marry"));*///14.获取元素的索引值/*int index = list.indexOf("Marry");System.out.println("Marry 的索引位置: " + index);*///15.判断 arrayList 是否为空/*System.out.println("arrayList 是否为空: " + list.isEmpty());*///16.截取 ArrayList 部分元素/*System.out.println("SubList: " + list.subList(0,1));*///17.toArray() 方法将 ArrayList 对象转化为数组//创建一个新的 String 类型数组/*String[] arr = new String[list.size()];list.toArray(arr);for (String s : arr) {System.out.println(s);}*///18.设定指定容量大小的 arrayList/*ArrayList<Integer> list2 = new ArrayList<Integer>();list2.ensureCapacity(3);list2.add(1);list2.add(2);System.out.println(list2.size());System.out.println(list2);*///19.返回指定元素在 arrayList 中最后一次出现的位置/*int index = list.lastIndexOf("Marry");System.out.println("Marry最后一次出现为止: " + index);*///20.保留 arrayList 中 在指定集合中也存在的那些元素//创建另一个动态数组/*ArrayList<String> site = new ArrayList<String>();site.add("Marry");site.add("Jhon");//保留元素list.retainAll(site);System.out.println("保留的元素:" + list);*///21.查看 arrayList 是否包含指定集合中的那些元素//创建一个动态数组/*ArrayList<String> site = new ArrayList<String>();site.add("Marry");site.add("Jhon");// 检查数组 list 是否包含 siteboolean b = list.containsAll(site);System.out.println(b);*///22.将 arrayList 中的容量调整为数组中的元素个数//调整容量/*list.trimToSize();System.out.println("ArrayList 大小: " + list.size());*///23.删除 arrayList 中指定索引之间存在的元素//删除所有满足特定条件的 arraylist 元素list.removeIf(e -> e.contains("Jh"));System.out.println("删除后的 ArrayList: " + list);}
}
五、泛型集合类型
1、介绍
在集合中泛型都是任意引用类型。既然是任意引用类型,也可以是集合类型。
2、实例化语法
List<List<Integer>> list = new ArrayList<>();
3、内存结构图
4、代码示例
public class Test {public static void main(String[] args) {List<List<Integer>> list = new ArrayList<>();List<Integer> list1 = new ArrayList<>();list1.add(1);list1.add(2);list1.add(3);List<Integer> list2 = new ArrayList<>();list2.add(11);list2.add(22);list2.add(33);list.add(list1);list.add(list2);for (List<Integer> integerList : list) {for (Integer i : integerList) {System.out.println(i);}}}
}
六、LinkedList
1、介绍
LinkedList 是 Java 中对双向非循环链表的实现,实现了List 接口。
具有 ArrayList 所有常用方法,额外还添加了头尾操作方法(实现了 Deque 方法),这些方法在 List 接口是不存在的,所以如果希望使用这些头尾操作方法,实例化时不用向上转型。
2、实例化语法
LinkedList<泛型> 对象 = new LinkedList<>()
3、常用 API
ArrayList 里面常用 API 都可以在 LinkedList 中使用。
public class TestLinkedList {public static void main(String[] args) {List<String> linkedList = new LinkedList<>();linkedList.addFirst("aa");linkedList.addLast("bb");//获取头结点 没有头结点 java.util.NoSuchElementExceptionString first = linkedList.getFirst();System.out.println(first);//获取尾结点 没有尾结点 java.util.NoSuchElementExceptionString last = linkedList.getLast();System.out.println(last);//获取头结点 没有头结点 返回 nullString s = linkedList.peekFirst();System.out.println(s);//获取尾结点 没有尾结点 放回 nullString s1 = linkedList.peekLast();System.out.println(s1);//删除头结点 没有头结点 java.util.NoSuchElementExceptionString s2 = linkedList.removeFirst();System.out.println(s2); //被删除结点中的值//删除尾结点 没有尾结点 java.util.NoSuchElementExceptionString s3 = linkedList.removeLast();System.out.println(s3);//被删除结点中的值//删除头结点 没有头结点 返回 nullString s4 = linkedList.pollFirst();System.out.println(s4);//删除尾结点 没有尾结点 放回 nullString s5 = linkedList.pollLast();System.out.println(s5);}
}
七、Set 接口
1、介绍
Set 继承了 Collection 接口,继承的都是 Collection 中的方法,没有提供额外的方法。
Set 经常被称为实现无序,不重复数据集合,指的就是 HashSet 实现类。
2、包含API
八、HashSet
1、介绍
完全基于 HashMap (数组 + 链表 + 红黑树)实现的。
存储无序,无下标,元素不重复数据
2、代码示例
public class TestHashSet {public static void main(String[] args) {Set<Integer> set = new HashSet<>();//添加元素set.add(1);set.add(2);//元素个数int size = set.size();//是否包含指定的元素boolean contains = set.contains(1);ArrayList<Integer> list = new ArrayList<>();list.add(3);list.add(4);list.add(4);//将其它集合中的元素添加到set集合中set.addAll(list);//删除指定的元素set.remove(2);//查询元素for (Integer integer : set) {System.out.println(integer);}}
}
九、TreeSet
1、介绍
底层是基于 TreeMap 红黑树。
public class TestTreeSet {public static void main(String[] args) {Set<Integer> treeSet = new TreeSet<>();treeSet.add(2);treeSet.add(1);treeSet.add(3);//查询元素for (Integer integer : treeSet) {System.out.println(integer);}}
}
十、Map 接口
1、接口
Map 是独立的接口。和 Collection 没有关系。
Map 中每个元素都是 Entry 类型,每个元素都包含 Key(键)和 Value(值)
2、继承关系
3、包含的API
十一、HashMap
1、介绍
HashMap 是对散列表的具体实现。
里面都包含 Key-Value 值。
2、代码演示
import java.util.HashMap;public class TestHashMap {public static void main(String[] args) {HashMap<Integer, String> sites = new HashMap<>();sites.put(1, "Google");sites.put(2, "Runoob");sites.put(3, "Taobao");System.out.println(sites);//1.访问元素/*System.out.println(sites.get(2));*///2.删除元素/*sites.remove(2);System.out.println(sites);*///3.删除所有键值对/*sites.clear();System.out.println(sites);*///4.计算大小/*System.out.println(sites.size());*///5.迭代 HashMap/*for (Integer integer : sites.keySet()) {System.out.println("key:" + integer + "value" + sites.get(integer));}*//*for (String value : sites.values()) {System.out.println(value);}*///6.赋值一份 hashMap/*Object clone = sites.clone();System.out.println(clone);*//*HashMap<Integer, String> clone = (HashMap<Integer, String>)sites.clone();System.out.println(clone);*///7.检查 HashMap 是否为空/*boolean empty = sites.isEmpty();System.out.println(empty);*///8.将所有键值对插入到 HashMap/*HashMap<Integer, String> site1 = new HashMap<>();site1.put(4, "Tom");site1.put(5, "Wiki");sites.putAll(site1);System.out.println(sites);*///9.判断 key 是否存在,不存在则将键/值插入到 HashMap 中/*sites.putIfAbsent(2, "Wiki");sites.putIfAbsent(4, "Wiki");System.out.println(sites);*///10.检查 hashMap 中是否存在 指定 key 对应的映射关系/*boolean b = sites.containsKey(2);System.out.println(b);*///11.检查 hashMap 中是否存在 指定 value 对应的映射关系/*if (sites.containsValue("Taobao")) {System.out.println("Taobao存在于 sites 中。");}*///12.替换 hashMap 中指定 key 对应的 value/*String wiki = sites.replace(2, "Wiki");System.out.println(wiki);System.out.println(sites);*//*boolean replace = sites.replace(2, "Runoob", "Wiki");System.out.println(replace);System.out.println(sites);*///13.将 hashMap 中所有映射关系替换成给定的函数所执行的结果/*sites.replaceAll((key, value) -> value.toUpperCase());*//*System.out.println(sites);*///14.获取指定的 key,不存在返回默认值/*String wiki = sites.getOrDefault(2, "Wiki");System.out.println(wiki);*///15.forEach()方法的使用/*sites.forEach((key, value) -> {value = value + "--HAHA";System.out.println(key + "=" + value + "");});*///16.返回映射中包含的映射的 set 视图/*System.out.println(sites.entrySet());*///17.获取映射 中所有 key 组成的 set 视图/*System.out.println(sites.keySet());*///18.获取映射 中所有 value 组成的 set 视图/*System.out.println(sites.values());*///19.merge 先判断指定的 key 是否存在,如果不存在,则添加键值对到 hashMap 中/*String wiki = sites.merge(4, "Wiki", (oldVaule, newValue) -> oldVaule + newValue);System.out.println(wiki);System.out.println(sites);*///20.compute() 方法对 hashMap 中指定的 key 的值进行重新计算/*String compute = sites.compute(3, (key, value) -> value + "HAHA");System.out.println(compute);System.out.println(sites);*///21.对 hashMap 中指定的 key 值进行重新计算,如果不存在这个 key,则添加到 hashMap 中/*String s = sites.computeIfAbsent(4, key -> "Wiki");System.out.println(s);System.out.println(sites);*///22.对 hashMap 中指定的 key 的值进行重新计算,前提 是该 key 存在于 hashMap 中String s = sites.computeIfPresent(3, (key, value) -> value + "HAHAHA");System.out.println(s);System.out.println(sites);}
}
十二、TreeMap
1、简介
红黑树的具体实现
2、代码实例
总体和 HashMap 使用非常类似
public class TestTreeMap {public static void main(String[] args) {Map<Integer, String> treeMap = new TreeMap<>();treeMap.put(2, "bb");treeMap.put(1, "aa");treeMap.put(3, "cc");for (Map.Entry<Integer, String> entry : treeMap.entrySet()) {System.out.println(entry.getKey() + ":" + entry.getValue());}}
}
十三、Iterator
1、简介
迭代器,是一个接口,每个集合中实现类都对 Iterator 提供了内部的实现。
通过 Iterator 可以实现遍历集合的效果。
存在意义:
隐藏集合实现细节,无论是哪种集合都是通过 Iterator 进行操作,而不是直接操作集合。通过一套 API 实现所有集合的变量。
可以在遍历时删除集合中的值。
2、实例化
每个实现类都提供了 .iterator();返回值就是迭代器对象。
public class TestIterator {public static void main(String[] args) {List<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(3);//获取集合的迭代器Iterator<Integer> iterator = list.iterator();//.hasNext() 判断是否有下一个元素while (iterator.hasNext()) {//获取下一个元素Integer next = iterator.next();System.out.println(next);}}
}
3. ConcurrentModificationException
在循环遍历集合时,向集合中插入值或删除集合中值时会出现这个异常。
public class Test {public static void main(String[] args) {List<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(3);for (Integer integer : list) {list.remove(integer);}}
}
异常截图:
为什么使用 for(int i = 0; i < list.size(); i++){} 时不出现这个异常?
因为这种循环其实是多次执行 get,调用 get() 方法时,集合 对其他元素删除 或新增是没有要求的。而增强 for 循环是把集合看作哟个整体,在遍历集合时,不允许对整个集合进行操作。
4、遍历集合时删除元素的内容
public class Test {public static void main(String[] args) {List<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(3);//获取集合的迭代器Iterator<Integer> iterator = list.iterator();//.hasNext() 判断是否有下一个元素while (iterator.hasNext()) {//获取下一个元素Integer next = iterator.next();//删除当前元素iterator.remove();}}
}
十四、Collections
1、介绍
Collections 是一个工具类型,一个抓们操作集合的工具类。
2、代码示例
public class TestCollections {public static void main(String[] args) {List<Integer> list = new ArrayList<>();list.add(2);list.add(1);list.add(3);//将集合中的元素排序Collections.sort(list);for (Integer integer : list) {System.out.println(integer);}//将多个元素添加到集合中Collections.addAll(list, 4, 6, 5);//获取集合中最大值Integer max = Collections.max(list);//获取集合中最小值Integer min = Collections.min(list);}
}
十五、不定项参数
1、简介
不定项参数必须在方法定义时,最后一个方法参数。
调用包含不定项参数的方法时,不定项参数位置,可以传递 0 到 任意个指定类型的参数。
方法内部,把不定项参数当做 数组使用即可。
2、代码示例
public class TestArgs {public static void main(String[] args) {test("zs"); //没有传值, 数组长度为0test("ls", 1, 2, 3); //传值, 数组长度为3}public static void test(String name, int... i){System.out.println(i);System.out.println(Arrays.toString(i));}
}