集合
可以将集合分为2个大类

Collection接口
API方法:

注意Collection是接口,需要子类才能实现,里面只能存储引用类型,所以会进行自动拆箱和装箱。
遍历:
增强for,还有迭代器遍历
// 迭代器遍历Iterator it = col.iterator();while (it.hasNext()) {System.out.println(it.next());}
实现类以及子接口
图示:

List接口
ArrayList实现类源码
JDK1.7
类中的成员变量

初始化,在JDK1.7中会默认初始化成员变量elementData数组的大小为10

对应的内存关系

add()方法

- 如果数组的10个位置都满后,就开始进行数组的扩容,扩容长度为原数组的1.5倍
- 判断是否扩容

- 扩容步骤

总结:底层数组,在调用构造器的时候,数组长度初始化10,扩容的时候扩展为原数组的1.5倍
JDK1.8
类中的成员变量,和1.7一致。

new 一个对象时的初始化,注意此时初始化数组的大小为一个常量,而常量值为0,则JDK1.8中初始化并没有申请一个长度为10的数组。


add方法

- 调用初始化方法

- 此时在参数中会调用初始化扩容大小的方法


- 此时minCapacity已经被赋值为10,与原数组大小比较判断是否进行扩容

- 此时才是grow的扩容实现

总结:底层数组实现,在调用构造器的时候,底层数组为f,在调用add方法以后底层数组才重新赋值为新数组,新数组的长度为10-》节省了内存,在add后才创建长度为10的数组。
Vector实现类
成员变量,也是数组实现

初始化值,为10


add方法
- 注意add方法加了锁,所以是线程安全的
- 扩容中间步骤和ArrayList大致一样
- 扩容步骤,注意此时扩容的大小是原数组2倍,而不是1.5倍
总结:都是数组进行实现,但和ArrayList的区别就是,线程安全,扩容的大小是2倍,因此造成了效率低,所以被弃用。
LinkedList实现类
LinkedList时有双向链表实现
transient int size = 0; // 节点个数/*** Pointer to first node.* Invariant: (first == null && last == null) ||* (first.prev == null && first.item != null)*/transient Node<E> first; // 前节点/*** Pointer to last node.* Invariant: (first == null && last == null) ||* (last.next == null && last.item != null)*/transient Node<E> last; // 后节点/*** Constructs an empty list.*/public LinkedList() { // 构造方法}public LinkedList(Collection<? extends E> c) {this();addAll(c);}
add方法:
- 会返回boolean类型
public boolean add(E e) {linkLast(e);return true;}
- 调用linkLast方法,方法实现
/*** Links e as last element.*/void linkLast(E e) {final Node<E> l = last; // 创建一个节点,作为最后一个节点的临时值final Node<E> newNode = new Node<>(l, e, null); // 此时添加节点在最后的位置,l作为前节点,null作为后节点last = newNode; // 赋值给last,更新最后一个元素if (l == null) // 如果添加的时第一个元素first = newNode; // 将第一个节点指向newNode节点elsel.next = newNode; // 如果不是,进行连接,l指向新生成的节点size++; // 大小加一modCount++;}
get方法:
- getLast()和getFirst()方法直接通过first和last节点取值即可,而get方法有些区别:
public E get(int index) {checkElementIndex(index); // 健壮性检查return node(index).item;}
node方法的具体实现,注意优化步骤
Node<E> node(int index) {// assert isElementIndex(index);if (index < (size >> 1)) { // 将链表分成两半,提高检索效率,如果此时查找的元素在前半部分,那么从first开始向后查找Node<E> x = first;for (int i = 0; i < index; i++)x = x.next;return x;} else { // 如果在后半部分,从last元素开始向前查找Node<E> x = last;for (int i = size - 1; i > index; i--)x = x.prev;return x;}}
Iterator迭代器
- 接口关系
- 可以知道Itr类是ArrayList的内部类
- Itr具体实现,Itr方法可以调用ArrayList的成员变量,也就是通过cursor表示代表指针来操作数组。
ListIterator迭代器
用于允许程序员沿任一方向遍历列表的列表的迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置。
常用方法

测试遍历方法
public class ListIteratorTest {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("aa");list.add("bb");list.add("cc");list.add("dd");list.add("ee");// 将ff插入cc的后面// Iterator<String> it = list.iterator();// while (it.hasNext()) {// if ("cc".equals(it.next())) {// list.add("ff"); // 报错ConcurrentModificationException,就是迭代器和list共同操作数组// }// }// 此时可以使用LinkIterator操作数组ListIterator<String> it1 = list.listIterator();while (it1.hasNext()) {if ("cc".equals(it1.next())) {it1.add("ff"); // 此时都是迭代器来操作}}System.out.println(list); // [aa, bb, cc, ff, dd, ee]// 可以逆向遍历while (it1.hasPrevious()) {System.out.println(it1.previous()); // ee dd ff cc bb aa}}}
后序遍历
Set接口
HashSet实现类
此类实现Set接口,由哈希表(实际为HashMap实例)支持。对集合的迭代次序不作任何保证;特别是,它不能保证订单在一段时间内保持不变。这个类允许null元素。
这个类提供了基本操作(add,remove,contains和size)固定的时间性能,假定哈希函数将分散的桶中正确的元素。 迭代此集合需要与HashSet实例的大小(元素数量)和后台HashMap实例(桶数)的“容量”的总和成比例的时间。 因此,如果迭代性能很重要,不要将初始容量设置得太高(或负载因子太低)是非常重要的。
请注意,此实现不同步。
常用方法
可以看出hashset没有关于索引的方法。

在add元素时,如果没有重写equals方法,那么set将不能判重。
原理图

比较器
比较int
int a = 10;int b = 20;System.out.println(a-b); // =0 >0 <0
比较double
double a = 9.6;double b = 9.3;/* System.out.println((int)(a-b));*/System.out.println(((Double) a).compareTo((Double) b));
比较String
String a = "A";String b = "B";System.out.println(a.compareTo(b));
比较自定义类型
内部比较器
实现Comparable接口,重写compareTo方法public class Student implements Comparable<Student> {private int age;private double height;private String name;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public double getHeight() {return height;}public void setHeight(double height) {this.height = height;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Student(int age, double height, String name) {this.age = age;this.height = height;this.name = name;}@Overridepublic String toString() {return "Student{" +"age=" + age +", height=" + height +", name='" + name + '\'' +'}';}@Overridepublic int compareTo(Student o) {// 以年龄进行比较// return this.age - o.getAge();// 以name进行比较return this.getName().compareTo(o.getName());}}
- 外部比较器
可以自己写一个类,也可以使用匿名内部类public class ComparatorTest {public static void main(String[] args) {// 比较两个自定义类型Student s1 = new Student(14, 160.5, "alili");Student s2 = new Student(14, 170.5, "bnana");Comparator<Student> com = new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {// 按照年龄进行比较return o1.getAge() - o2.getAge();}};System.out.println(com.compare(s1, s2));}}
TreeSet实现类
TreeSet和HashSet一样,保证了元素时唯一,但内部使其排列(可以自定义比较器来控制其升序还是降序)。但升序的比较是按照比较器来定义。
常用方法
查api
原理结构图
底层逻辑结构便是二叉搜索树,通过比较器进行比较来判断往哪放,输出的话逻辑上就是中序遍历,保证升序输出。

使用实例
如果在TreeSet中加入String和Integer等包装类类型的话TreeSet会自动排序,因为包装类中都实现了内部比较器。
例如Double:

而自定义类需要自己定义
- 内部比较器需要类实现Comparable接口,重写compareTo方法
- 外部比较器
public class TreeSetTest {public static void main(String[] args) {//创建一个TreeSet:TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {// 按照年龄进行升序return o1.getAge() - o2.getAge();}});ts.add(new Student(10, 180, "elili"));ts.add(new Student(8, 184, "blili"));ts.add(new Student(4, 165, "alili"));ts.add(new Student(9, 155, "elili"));ts.add(new Student(10, 143, "flili"));ts.add(new Student(1, 175, "dlili"));System.out.println(ts.size());System.out.println(ts);}}
外部比较器利用堕胎,扩展性好
Map接口
实现类以及子接口

常用方法
package com.msb.test11;import java.util.Collection;import java.util.HashMap;import java.util.Map;import java.util.Set;/*** @author : msb-zhaoss*/public class Test01 {//这是main方法,程序的入口public static void main(String[] args) {/*增加:put(K key, V value)删除:clear() remove(Object key)修改:查看:entrySet() get(Object key) keySet() size() values()判断:containsKey(Object key) containsValue(Object value)equals(Object o) isEmpty()*///创建一个Map集合:无序,唯一Map<String,Integer> map = new HashMap<>();System.out.println(map.put("lili", 10101010));map.put("nana",12345234);map.put("feifei",34563465);System.out.println(map.put("lili", 34565677));map.put("mingming",12323);/*map.clear();清空*//*map.remove("feifei");移除*/System.out.println(map.size());System.out.println(map);System.out.println(map.containsKey("lili"));System.out.println(map.containsValue(12323));Map<String,Integer> map2 = new HashMap<>();System.out.println(map2.put("lili", 10101010));map2.put("nana",12345234);map2.put("feifei",34563465);System.out.println(map2.put("lili", 34565677));map2.put("mingming2",12323);System.out.println(map==map2);System.out.println(map.equals(map2));//equals进行了重写,比较的是集合中的值是否一致System.out.println("判断是否为空:"+map.isEmpty());System.out.println(map.get("nana"));System.out.println("-----------------------------------");//keySet()对集合中的key进行遍历查看:Set<String> set = map.keySet();for(String s:set){System.out.println(s);}System.out.println("-----------------------------------");//values()对集合中的value进行遍历查看:Collection<Integer> values = map.values();for(Integer i:values){System.out.println(i);}System.out.println("-----------------------------------");//get(Object key) keySet()Set<String> set2 = map.keySet();for(String s:set2){System.out.println(map.get(s));}System.out.println("-----------------------------------");//entrySet()Set<Map.Entry<String, Integer>> entries = map.entrySet();for(Map.Entry<String, Integer> e:entries){System.out.println(e.getKey()+"----"+e.getValue());}}}
TreeMap
和TreeSet使用一样,需要实现内部或者外部比较器
HashMap
HashMap底层代码细节参照🔗
红黑树介绍参照🔗
