标签:Node return int next key 集合 null
源码分析
如何看源码:
脉络 解决什么问题,忽略掉不重要的一些细节
构造 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<T> 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<Student>() {
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<String> list =new ArrayList<String>(20);//1
ArrayList<String> list =new ArrayList<String>();//3
ArrayList<String> list =new ArrayList<String>(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集合只能读写,不能增删
9.2 LinkedList
无参构造:
public LinkedList() {
}
public boolean add(E e) {
linkLast(e);//后面添加元素
return true;
}
//链表的节点
private static class Node<E> {
E item;//数据---“aaa”
Node<E> next;//后继
Node<E> prev;//前驱
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
//添加元素
void linkLast(E e) {
final Node<E> l = last;//先把最后一个节点缓存起来
//这个节点是要添加的节点,前驱是上次最后的节点,后继为空
final Node<E> 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<E> x = first; x != null; x = x.next) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
//遍历所有的节点,判断内容相等即删除,然后返回,循环完都找不到就返回false
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
E unlink(Node<E> x) {
// assert x != null;
final E element = x.item;//删除的值先保存一下,最后返回去
final Node<E> next = x.next;//后继节点
final Node<E> prev = x.prev;//前驱节点
if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
}
if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}
x.item = null;//释放对象,提醒垃圾回收线程回收垃圾
size--;
modCount++;
return element;
}
list.get(index):
public E get(int index) {
checkElementIndex(index);//下标检查
return node(index).item;
}
Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
9.3 HashMap
无参构造:
public HashMap() {
//loadFactor:加载因子
//static final float DEFAULT_LOAD_FACTOR = 0.75f;
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
put:
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
//hash
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
//0101010101010110110101 --高16位移位低16位
}
//设值的方法
//内部类
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
transient Node<K,V>[] table;//哈希桶
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
//第一次桶为空
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;//hash桶的扩容---第一次 --- 16,阈值是12 //通过桶的下标获取到桶里的元素--null,单节点,链表,红黑树
if ((p = tab[i = (n - 1) & hash]) == null)
//i = (n - 1) & hash 1010010101101010100010100---0
// 0000000000000000000001111
// 0000000000000000000000100
//n=10 0000000000000000000001001
//
//这个位置没有别人,new 节点放进去
tab[i] = newNode(hash, key, value, null);
else {
//节点,链表,红黑树
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;//保存相同的节点
else if (p instanceof TreeNode)
//如果这个桶里存的是个红黑树
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
//链表
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
//static final int TREEIFY_THRESHOLD = 8
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);//solidify
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
final Node<K,V>[] resize() {
Node<K,V>[] oldTab = table;//缓存原来的hash桶
int oldCap = (oldTab == null) ? 0 : oldTab.length;
int oldThr = threshold;//阈值--0
int newCap, newThr = 0;
if (oldCap > 0) {
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
}
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // double threshold
}
else if (oldThr > 0) // initial capacity was placed in threshold
newCap = oldThr;
else { // zero initial threshold signifies using defaults
//默认第一次从0扩展到16
newCap = DEFAULT_INITIAL_CAPACITY;//static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);//12
}
if (newThr == 0) {
float ft = (float)newCap * loadFactor;
newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
(int)ft : Integer.MAX_VALUE);
}
threshold = newThr;
//创建新桶,把原来的元素放到新桶里返出去
@SuppressWarnings({"rawtypes","unchecked"})
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
table = newTab;
if (oldTab != null) {
for (int j = 0; j < oldCap; ++j) {
Node<K,V> e;
if ((e = oldTab[j]) != null) {
oldTab[j] = null;
if (e.next == null)
newTab[e.hash & (newCap - 1)] = e;
else if (e instanceof TreeNode)
((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
else { // preserve order
Node<K,V> loHead = null, loTail = null;
Node<K,V> hiHead = null, hiTail = null;
Node<K,V> next;
do {
next = e.next;
if ((e.hash & oldCap) == 0) {
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
}
else {
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}
}
}
}
return newTab;
}
带参构造:
public HashMap(int initialCapacity) {//10
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);
}
//这个方法就是保证2的n次方的
static final int tableSizeFor(int cap) {//10
int n = cap - 1;//1001 //0111
n |= n >>> 1; //1100
n |= n >>> 2; //1111 //1000
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;//0000010000
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
1、HashMap无参构造第一次扩到16个桶,加载因子是0.75f,阈值是12
2、key的hash值是这个key对应的hashcode()高十六位移位低十六位与原值做异或运算得到的---散
3、元素放哪个桶里取决于key得到的hash与n-1做位与运算,这里要求hash桶的长度必须是2的n次方,如果不是,则有一些桶里面永远不可能有元素。
4、HashMap如何保证这个长度是2的n次方,无参构造默认使用16,以后每次扩容都是2倍,带参构造会自动运算成大于等于这个长度值的最近的2的n次方的数。
5、如果Key的hash值一样,默认是替换原来的值。
6、如果这个桶里面是一个链表,那么链表元素的个数达到8的时候就会转为红黑树。同样的如果树的元素达到6的时候再转为链表。转换的前提是hash桶的个数要达到64。
7、如果hash桶扩容了,原来的元素会不会换桶---会--rehash
null做键?这个元素在哪里?
LinkedHashMap:多维护了一个双向链表
9.4 TreeMap
public TreeMap() {
comparator = null;
}
//put方法
public V put(K key, V value) {
Entry<K,V> t = root;//根节点
if (t == null) {
compare(key, key); // type (and possibly null) check
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
// split comparator and comparable paths
Comparator<? super K> cpr = comparator;
if (cpr != null) {//构造进去的Comparator比较器
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
else {//使用类实现Comparable这个接口的比较器
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);//book t.key = book
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
Entry<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
//取值
get
public V get(Object key) {
Entry<K,V> p = getEntry(key);
return (p==null ? null : p.value);
}
final Entry<K,V> getEntry(Object key) {
// Offload comparator-based version for sake of performance
if (comparator != null)
return getEntryUsingComparator(key);
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
Entry<K,V> p = root;
while (p != null) {
int cmp = k.compareTo(p.key);
if (cmp < 0)
p = p.left;
else if (cmp > 0)
p = p.right;
else
return p;
}
return null;
}
ArrayList不可修改问题
第一次扩容到16
阈值为16*0.72=12
8
标签:Node,return,int,next,key,集合,null 来源: https://www.cnblogs.com/chahune/p/16482646.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。