集合源码

源码分析

如何看源码:
脉络 解决什么问题,忽略掉不重要的一些细节
构造 add remove
理解代码运行过程
ArrayList
集合1

1、集合框架--Collection

2、ArrayList 和LinkedList

ArrayList:基于数组实现,查询效率高

LinkedList:基于链表实现,增删效率高

size():长度

add():添加

remove():删除

clear():清空

set():修改

3、泛型

限制类型

不用转型

泛型:<>

4、Collections

shuffle:

Collections.reverse(list);反转集合

Collections.checkedList(dogs,Dog.class):对加入数据的类型进行检查

5、HashSet

hashCode:确定桶的
equals:比较是否同一个对象,决定了这个元素是丢是留

LinkedHashSet是在HashSet的基础上新维护了一个双向链表

6、TreeSet

树:二叉树

两种排序:

用匿名内部类在构造TreeSet的时候放一个Comparator

用需要排序的类去实现Comparable

7、迭代器

iterator

Collection extends Iterable;

意味着只要是Collection的儿子都有迭代器

//获取迭代器
Iterator itor = 集合.iterator();
//while
while(itor.hasNext()){
T t = itor.next();
}
注意:迭代器可以在迭代的同事删除当前元素

反向迭代器

8、Map

8.1 HashMap<K,V>

put(k,v);

remove(key)

get(key)

keySet():key的集合----Set

values():Collection

entrySet():Set<Entry<K,V>>

containsKey():是否包含这个键

8.2 Hashtable

线程安全的,效率低,使用少,键值不能为null

Properties类:

编写配置文件

8.3 LinkedHashMap

public static void main(String[] args) {
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
map.put("CN", "CHINA");
map.put("US", "AMERICA");
map.put("RU", "RUSSIA");
map.put("JP", "JAPAN");
map.put("FR", "FRANCE");
map.put("UK", "UNITEDKINGDON");
System.out.println(map);
}

8.4 TreeMap

public static void main(String[] args) {
TreeMap<Student, String> map = new TreeMap<Student, String>(new Comparator() {
public int compare(Student o1, Student o2) {
return o1.salary-o2.salary;
}
});
map.put(new Student("中国",50,10), "CHINA");
map.put(new Student("美国",20,21), "AMERICA");
map.put(new Student("俄国",30,23), "RUSSIA");
map.put(new Student("日本",40,34), "JAPAN");
map.put(new Student("法国",60,34), "FRANCE");
map.put(new Student("英国",100,66), "UNITEDKINGDON");
System.out.println(map);
}

9、源码分析

如何看源码:

脉络---解决什么问题,忽略掉不重要的一些细节

构造---》add--->remove

9.1 ArrayList

ArrayList list =new ArrayList(20);//1
ArrayList list =new ArrayList();//3
ArrayList list =new ArrayList(0);//1,2,3,4,6,9,13,19,28//9
list.add("111");
这两种方式定义集合,当集合长度达到20时,分别经历了多少次扩容?

public ArrayList() {
//构造一个无参的对象,就把一个空数组赋给elementData,这个数组实际上就是
//ArrayList的底层数据存储的地方
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;//{};
}
//私有静态常量对象数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//对象数组的属性
transient Object[] elementData;

//添加方法
public boolean add(E e) {
ensureCapacityInternal(size + 1); //private int size;---默认为0
elementData[size++] = e;
return true;
}

private void ensureCapacityInternal(int minCapacity) {//1
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));//{}-DEFAULTCAPACITY_EMPTY_ELEMENTDATA,1 ---10
}

private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//无参构造第一次满足
return Math.max(DEFAULT_CAPACITY, minCapacity);
// private static final int DEFAULT_CAPACITY = 10;
}
return minCapacity;
}

private void ensureExplicitCapacity(int minCapacity) {//10
modCount++;

// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);//扩容-10
}

private void grow(int minCapacity) {//10--1
// overflow-conscious code
int oldCapacity = elementData.length;//0
int newCapacity = oldCapacity + (oldCapacity >> 1);//0
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;//10
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);//扩容
}

以上是无参构造的执行过程

public ArrayList(int initialCapacity) {//20
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}

//modCount--模数 魔数 魔术
这个变量记录的是集合操作的次数---增删

//remove
public E remove(int index) {//下标
rangeCheck(index);

modCount++;
E oldValue = elementData(index);

int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work

return oldValue;
}

//get

1、ArrayList在无参构造的时候,设置对象数组为空

2、如果是无参构造出来的空集合,一开始长度为0,第一次执行添加操作的时候,会扩容到10

3、以后ArrayList满了的时候就会按照1.5倍进行扩容

4、如果构造的是带参的,那么直接扩容到参数指定的个数,特例如果参数为0,就从0开始扩容

源码解决ArrayList不可修改的问题

Arrays类里有一个ArrayList的内部类,这个类没有实现add,remove方法发,而是直接抛异常

String[] strs = {"aaa","bbb","ddd"};
List list = Arrays.asList(strs);

这样得到的list集合只能读写,不能增删

9.2 LinkedList

无参构造:
public LinkedList() {
}

public boolean add(E e) {
linkLast(e);//后面添加元素
return true;
}
//链表的节点
private static class Node {
E item;//数据---“aaa”
Node next;//后继
Node prev;//前驱

Node(Node prev, E element, Node next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
//添加元素
void linkLast(E e) {
final Node l = last;//先把最后一个节点缓存起来
//这个节点是要添加的节点,前驱是上次最后的节点,后继为空
final Node newNode = new Node<>(l, e, null);
//成员变量last保存当前要添加的节点为最后节点
last = newNode;
if (l == null)
//第一个节点,first=last=newNode
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}

//删除指定元素
public boolean remove(Object o) {
if (o == null) {
for (Node x = first; x != null; x = x.next) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {

posted @ 2022-07-15 20:32  yishizhengbianren  阅读(150)  评论(0)    收藏  举报