1 数组与集合
1.1 集合与数组存储数据概述
- 集合、数组都是对多个数据进行存储操作的结构,简称Java容器。
说明:此时的存储,主要是指的是内存层面的存储,不涉及到持久化的存储。
1.2数组存储特点
- 一旦初始化后,其长度就确定了。
- 数组一旦定义好,其元素类型也就确定了。我们只能操作指定类型的数据。
String[] arr = new String[4];//数组类型和长度确定
String[] arr2 = new String[]{"123", "AA", "cc"};//数组类型和长度确定
int[] arr3;
Object[] arr4;
1.3 数组存储的弊端
①一旦初始化后,其长度就不可修改
②数组中提供的方法非常有限,对于添加、删除、插入数据等操作,非常不便,同时效率不高。
③获取数组中实际元素的个数的需求,数组中没有现成的属性或方法可用。
④数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足。
1.4集合存储的优点
解决数组存储数据方面的弊端
2 Collection接口
2.1 单列集合框架结构
/----Collection接口:单列集合,用来存储一个一个的对象
/----list接口:存储有序的、可重复的数据。 —>“动态的数组”
/----ArrayList、LinkedList、Vector
/----Set接口:存储无序的、不可重复的数据 —>高中的集合
/----HashSet、LinkedHashSet、TreeSet
2.2 Collection接口常用方法
- 有15个
add(Object obj)添加元素
addAll(Collection coll)将列表coll中的元素全部添加到当前列表
size()当前列表内的元素个数
isEmpty()判断当前列表是否为空
clear()清空当前列表
remove(Object obj) 删除元素
removeAll(Collection col)
removeIf
contains(Object obj)判断是否包含元素obj,返回boolean
containsAll(Collection coll)判断当前集合是否包含集合coll,返回boolean
retainAll(Collection coll),取当前集合和coll的交集,赋给当前集合,有返回值,返回值的类型为boolean
equals()判断两个集合是否相等
hasCode(),返回当前集合的哈希值
toArray(),列表转数组,返回一个Objcet类型的数组
iterator(),返回一个当前集合的迭代器
2.3 Collection集合与数组之间的转换
集合—>数组:toArray()
//toArray()集合转数组,转换成了一个Object类型的数组
Object[] objects = coll1.toArray();
//foreach循环(增强for循环)
for (Object o : objects) {
System.out.println(o);
}
数组—>集合:调用Arrays类的静态方法asList(T … t0)
//数组转集合
List<String> strings = Arrays.asList(new String[]{"AA", "BB", "CC"});
System.out.println(strings);
//需要注意的是!基本数据类型的数组,为被认为是一个元素~
//所以如果要解决这个问题,需要使用包装类
List<int[]> ints = Arrays.asList(new int[]{123, 333, 90});
System.out.println(ints);
List<Integer> integers = Arrays.asList(new Integer[]{11, 22, 34});
System.out.println(integers);
2.4 Collection集合存储对象的注意点
- 向Collection接口的实现类的对象中添加obj时,要求obj所在类要重写equals()
2.5 删除Collection元素的三种方式
Collection collection = new ArrayList();
collection.add("java");
collection.add("bigdata");
collection.add("python");
collection.add("bigdata");
collection.add("bigdata");
//方式一:iterator.remove()
//区别于:collection.remove(Object obj)
Iterator iterator = collection.iterator();
while (iterator.hasNext()){
if (iterator.next().equals("bigdata")){
iterator.remove();
}
}
//方式二:contains(Object obj)
while(collection.contains("bigdata")){
collection.remove("bigdata")
}
//方式三:removeAll(Collection coll)
Collection coll = new ArrayList();
coll.add("bigdata");
collection.removeAll(coll);
3 Iterator接口与foreach循环
3.1 遍历Collection的两种方式
- 使用迭代器Iterator
Iterator iterator = coll.iterator();
//遍历集合
while(iterator.hasNext()){
System.out.println(iterator.next());
}
- 使用foreach循环
//快捷键时iter
Object[] objects = coll1.toArray();
for (Object o : objects) {
System.out.println(o);
}
3.2 Iterator迭代器
- java.utils包下定义的迭代器接口:Iterator
- Iterator对象称为迭代器(设计模式中的一种),主要用于遍历Collection集合中的元素。
iterator迭代器的源码分析
Collection collection = new ArrayList();
collection.add("java");
collection.add("bigdata");
collection.add("python");
collection.add("bigdata");
collection.add("bigdata");
Iterator iterator = collection.iterator();
while (iterator.hasNext()){
if (iterator.next().equals("bigdata")){
iterator.remove();
}
}
//iterator()
/*
Iterator 是一个接口,coll调用iterator(),生成一个iterator迭代器是调用ArrayList内的iterator()方法,return new Itr();返回一个Itr对象,Itr实现了Iterator接口;Itr是ArrayList内的一个内部类,它有三个属性,cursor返回值的游标索引值、lastRet辅助游标cursor-1;modCount操作数。
源码:
Collection coll = new ArrayList();
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
int cursor; // 游标,从0开始
int lastRet = -1; // 游标上一个,从-1开始
int expectedModCount = modCount;//操作的次数
*/
//hasNext()
/*
运行时看ArrayList的hasNext();判断游标索引和有效个数。
源码:
public boolean hasNext() {
return cursor != size;
}
*/
//next()
/*
ArrayList的iterator的next方法,
源码:
public E next() {
checkForComodification();//检查异常
checkForComodifcation()的内部源码
final void checkForComodification() {
if (modCount != expectedModCount)//判断集合的操作数和迭代器的操作数是否相等。
throw new ConcurrentModificationException();
}
int i = cursor;//定义一个辅助游标,帮助遍历数组;判断的目的
if (i >= size)//size数组的有限数据的个数
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;//Object[] elementData的地址指向将coll的数组的地址
if (i >= elementData.length)//length数组的实际长度,判断的目的是
throw new ConcurrentModificationException();
cursor = i + 1;//游标先下移,再返回上一个值。
return (E) elementData[lastRet = i];//返回游标的上一个值。
}
*/
//iterator.remove()
/*
源码:
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);//迭代器中的删除还是调用ArrayList中的remove()
cursor = lastRet;//删除一个后游标后移到lastRet位置。
lastRet = -1;
expectedModCount = modCount;//这是不报错的主要原因!
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
*/
//coll.remove()
/*
public E remove(int index) {
rangeCheck(index);
modCount++;//Collection中的删除操作数++,但是在上述checkForComodification(),导致next方法中的迭代器操作数与之不相等,会报异常。
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;
}
*/
- 迭代器中remove()的使用
- 如果还没调用next()或在上一次调用next方法之后,已经调用了remove方法,再调用remove都会报IllegalStateException
- 迭代器中定义的remove方法不同于Collection集合直接调用remove。
@Test
public void test1{
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person("Jerry",20));
coll.add(new String("Tom"));
coll.add(false);
//删除集合中"Tom"
Iterator iterator = coll.iterator();
while(iterator.hasNext()){
Object obj = iterator.next();
if("Tom".equals(obj)){
//调用iterator的remove()
iterator.remove();
}
}
//遍历集合
iterator = coll.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
3.3 foreach循环(增强for循环)
- jdk 5.0 新特性 – 增强for循环(foreach循环)
- 遍历集合举例:
@Test
public void test1(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person("Jerry",20));
coll.add(new String("Tom"));
coll.add(false);
//for(集合元素的类型 局部变量 : 集合对象)
for(Object obj : coll){
System.out.println(obj);
}
}
- 说明
内部仍然时调用了迭代器
- 遍历数组举例:
@Test
public void test2(){
int[] arr = new int[]{1, 2, 3, 4, 5};
//for(数组元素的类型 局部变量:数组对象)
for(int i : arr){
System.out.println(i);
}
}
4 Collection子接口:List接口
4.1 存储的数据的特点
存储有序的、可重复的数据
4.2 常用方法(记住!!!)
- 增:add(Object obj)
- 删:remove(Object obj) / remove(int index)
- 改:set(int index, Object obj)
- 查:get(int index)
- 插:add(int index, Object obj)
- 长度:size()
- 遍历:①Iterator迭代器方式
②增强for循环
③普通for循环
- 增加:add(Object obj) | add(int index, Object obj) | addAll(Collection coll) | addAll(int index, Collection coll)
- 注意:add(int index, Object obj),index下标索引值可以=size;但是不能间隔一个去插入
List list = new ArrayList(); list.add("java"); list.add(123); list.add("123L"); list.add(3, "hadoop");//这可以 list.add(8, "spark");//IndexOutOfBoundsException
- 删除:remove
- 修改
4.3 常用实现类
/----Collection接口:单列集合,用来存储一个一个的对象
/----List接口:存储有序的、可重复的数据。–>”动态数组“,替换原来的数组
/----ArrayList:作为List接口的主要实现类;
线程不安全
,效率高
;底层使用Object[] elementData存储
/----LinkedList:对于频繁的插入、删除操作,使用此类效率比ArrayList高;底层使用
双向链表存储
4.4 源码分析(难点)
ArrayList的源码分析
- jdk 7 的情况下
- ArrayList list = new ArrayList();//底层创建了长度为10的
Object[] 数组elementData
;- list.add(123);//elementData[0] = new Integer(123);
…
list.add(11);//如果此次的添加导致底层的elementData数组容量不够,则扩容。
- 默认情况下,扩容为原来的容量的1.5倍,同时需要将原有数组中的数据复制到新的数组中。
- 结论:建议开发中使用带参数的构造器:
ArrayList list = new ArrayList(int capacity)
- jdk 8 的情况下
- ArrayList list = new ArrayList(); //底层Object[] elementData初始化为{}。并没有创建长度为10的数组。
- list.add(123);//第一次调用add()时,底层才创建了长度为10的数组,并将数据123添加到elementData[0]
…
后续的添加和扩容操作与jdk 7 无异- 结论:jdk 7的ArrayList的对象的创建相当于类似单例的饿汉式,而jdk 8的ArrayList的对象的创建相当于懒汉式,延迟了数组的创建,节省内存。
//ArrayList的源码分析
@Test
public void testArrayList(){
List list = new ArrayList();
//增add(Object obj)
list.add("java");
list.add(123);
list.add(33);
list.add(14423);
list.add("123L");
list.add("123L");
list.add("123L");
list.add(5, "hadoop");
list.add("123L");
list.add("123L");
list.add("123L");
System.out.println(list);
}
/*
ArrayList里的属性:
this.elementData,是ArrayList的实例化对象的数组。
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//jdk1.8以后,默认初始的数组为空。在第一次添加的时候才扩容为10。
1. 初始化,new ArrayList();
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;//
}
2. 第一次添加的时候:
public boolean add(E e) {
ensureCapacityInternal(size + 1);//2.1,minCapacity = size + 1 //1
elementData[size++] = e;
return true;
}
2.1
private void ensureCapacityInternal(int minCapacity) {
//第一次添加的时候elementData==DEFAULT...都是空数组
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//最小容量 = max(10, 1) = 10
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);2.2
}
2.2
private void ensureExplicitCapacity(int minCapacity) {
modCount++;//操作数++
//如果最小容量 > 数组长度 ---> 10 > 0
if (minCapacity - elementData.length > 0)
grow(minCapacity);//2.3 扩容机制
}
2.3
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)//第一次添加的时候
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)//数组容量特别大的时候
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);//数组扩容
}
*/
LinkedList的源码分析
- LinkedList list = new LinkedList();内部声明了Node类型的first和last属性,属性值为null。
- List.add(123);//将123封装到Node中,创建了Node对象。
- 其中,Node定义为:体现了LinkedList的双向链表的说话
//LinkedList的源码分析 private static class Node<E> { E item; Node<E> next; Node<E> prev; Node(Node<E> prev, E element, Node<E> next) { this.item = element; this.next = next; this.prev = prev; } }
//LinkedList的源码分析
@Test
public void testLinkedList(){
List list = new LinkedList();
//增add(Object obj)
list.add("hadoop");
list.add(1024);
list.add("spark");
System.out.println(list);
}
/*
1. new LinkedList(),实例化LinkedList对象
public LinkedList() {//空参构造器
}
1.1 LinkedList的属性
transient int size = 0;
transient Node<E> first;//first和last都是Node类型的节点。LinkedList中只保存了头结点和尾节点的两个属性;还有size节点数量。
transient Node<E> last;
2. add()添加操作。
public boolean add(E e) {
linkLast(e);//2.1 添加元素
return true;
}
2.1
void linkLast(E e) {
final Node<E> l = last;//定义一个辅助节点,保存last节点;
final Node<E> newNode = new Node<>(l, e, null);//声明一个newNode节点。
last = newNode;//将链表中的last=newNode
if (l == null)//第一次添加的时候l = null,first = newNode
first = newNode;
else//不是第一次添加的时候,l.next = newNode
l.next = newNode;
size++;//每添加一个size++
modCount++;//每添加一个操作数++
}
*/
Vector的源码分析
jdk7和jdk8中通过Vector()构造器创建对象时,底层都创建了长度为10的数组。
在扩容方面,默认扩容为原来的数组长度的2倍。
//Vector的源码分析
@Test
public void testVector(){
List list = new Vector();
list.add("hadoop");
for (int i = 0; i < 9; i++) {
list.add("i" + i);
}
list.add(123);
System.out.println(list);
}
/*
源码:
1. new Vector(),创建Vector对象
public Vector() {
this(10);//默认初始容量为10;
}
2. add(),添加元素
public synchronized boolean add(E e) {
modCount++;//操作数++
ensureCapacityHelper(elementCount + 1);// 2.1判断是否需要扩容
elementData[elementCount++] = e;//添加元素到数组
return true;
}
2.1
private void ensureCapacityHelper(int minCapacity) {
if (minCapacity - elementData.length > 0)
grow(minCapacity);//扩容操作,第一次添加不需要扩容
}
3. 添加到第11个时,需要扩容,扩容为原容量的两倍
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
4. 另外需要说明的是,Vector的大部分方法是synchronize的,所以线程安全。
*/
4.5 存储的元素的要求
添加的对象,所在的类要重写equals()方法
[面试题]
- 面试题:ArrayList、LinkedList、Vector者的异同?
- 同:三个类都是实现了List接口,存储数据的特点相同:存储序的、可重复的数据
- 不同:见上(第3部分+第4部分)
5 Collection子接口:Set接口
5.1 存储的数据特点
无序的、不可重复的元素。
- 以HashSet为例说明:
- 无序性:不等于随机性。存储的数据在底层数组中并非照数据索引的顺序添加,而是根据数据的哈希值决定的。
- 不可重复性:保证添加的元素照equals()判断时,不能返回true。即相同的元素只能添加一个。
5.2 元素添加过程(以HashSet为例)
- 我们向HashSet中添加元素a,首先会调用元素a所在类的hashCode()方法,计算元素a的哈希值。
- 此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即为索引位置)
- 判断数组位置上是否已经有元素:
3.1 如果此位置上没有其他元素,则元素a添加成功。---->情况1
3.2 如果此位置上有其他元素b(或以链表的形式存在多个元素),则比较元素a与元素b的hash值:
3.2.1 如果hash值不相同,则元素a添加成功。---->情况2
3.2.2 如果hash值相同,进而需要调用元素a所在类的equals()方法:
3.2.2.1 equals()返回true,元素a添加失败
3.2.2.2 equals()返回false,元素a添加成功。---->情况3
- 对于jdk 7 和jdk 8 添加成功的情况2和情况3而言:
元素a与已经存在指定索引位置上的数据以链表的方式存储
jdk7 : 元素a放到数组中,指向原来的元素。
jdk8: 原来的元素在数组中,指向元素a
总结:七上八下
- HashSet底层:数组+链表的结构
5.3 常用方法
Set接口中没有额外定义新的方法,使用的都是Collection中声明的方法。
5.4 常用实现类
/----Collection接口:单列集合,用来存储一个一个的对象
/----Set接口:存储无序的、不可重复的数据—>高中讲的集合
/----HashSet:作为Set接口的主要实现类;线程不安全;可以存储null值;
/----LinkedHashSet:作为HashSet的子类;遍历其内部数据时,可以按照添加的顺序遍历,在添加数据的同时,每个数据还维护了两个引用,记录此数据前一个数据和后一个数据。
/----TreeSet:可以按照添加对象的指定属性,进行排序。
5.5 存储对象所在类的要求
- HashSet/LinkedHashSet
- 要求:向Set(主要指:HashSet、LinkedHashSet)中添加的数据,其所在的类一定要重写hashCode()和equals()
- 要求:重写的hashCode()和equals()尽可能保持一直;相等的对象必须具有相等的散列码
- 重写两个方法的小技巧:对象中用作equals()方法比较的Field,都应该用来计算hashCode值。
- TreeSet:
- 自然排序中,比较两个对象是否相同的标准为:compareTo()返回0,不再是equals()
- 定制排序中,比较两个对象是否相同的标准为:compare()返回0,不再是equals()
5.6 TreeSet的使用
使用说明
- 向TreeSet中添加的数据,要求是相同类的对象
- 两种排序方式:自然排序(实现Comparable接口 和 定制排序Comparator)
常用的排序方式
- 方式一:自然排序
@Test
public void test1(){
TreeSet set = new TreeSet();
//失败:不能添加不同类的对象
// set.add(123);
// set.add(456);
// set.add("AA");
// set.add(new User("Tom",12));
//举例一:
// set.add(34);
// set.add(-34);
// set.add(43);
// set.add(11);
// set.add(8);
//举例二:
set.add(new User("Tom",12));
set.add(new User("Jerry",32));
set.add(new User("Jim",2));
set.add(new User("Mike",65));
set.add(new User("Jack",33));
set.add(new User("Jack",56));
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
- 方式二:定制排序
@Test
public void test2(){
Comparator com = new Comparator() {
//照年龄从小到大排列
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof User && o2 instanceof User){
User u1 = (User)o1;
User u2 = (User)o2;
return Integer.compare(u1.getAge(),u2.getAge());
}else{
throw new RuntimeException("输入的数据类型不匹配");
}
}
};
TreeSet set = new TreeSet(com);
set.add(new User("Tom",12));
set.add(new User("Jerry",32));
set.add(new User("Jim",2));
set.add(new User("Mike",65));
set.add(new User("Mary",33));
set.add(new User("Jack",33));
set.add(new User("Jack",56));
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
6 Map接口
Map - 双列集合框架
6.1 常用实现类结构
/----Map:双列数据,存储key-value对的数据。—> 类似高中的函数:y = f(x)
/----HashMap:作为Map的主要实现类:线程不安全的,效率高;可以存储null的key和value
HashMap底层使用
数组+链表(jdk7及以前);数组+链表+红黑树(jdk8)
;/----LinkedHashMap:保证在遍历map元素时,可以按照添加的顺序实现遍历。
原因:在原来的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素。对于频繁的遍历操作,此类执行效率高于HashMap。
/----TreeMap:保证按照添加的key-value对进行排序,实现排序遍历。此时考虑key的自然排序或定制排序。
TreeMap底层使用
红黑树结构
/----Hashtable:作为古老的实现类:线程安全的,效率低,不能存储null的key和value
/----Properties:常用来处理匹配文件。key和value都是String类型。
【面试题】
- HashMap的底层实现原理?
- HashMap和Hashtable的异同?
- CurrentHashMap与Hashtable的异同?(暂时不讲)
6.2 存储结构的理解
- Map中的key:无序的、不可重复的,使用Set存储的key
key所在的类要重写equals()和hashCode() (以HashMap为例)
- Map中的value:无序的、可重复的,使用Collection存储value
value所在的类要重写equals()
- Map中的entry:无序的、可重复的,使用Set存储entry
一个键值对:key-value 构成一个Entry对象
6.3 常用的方法
- 添加:put(Object key, Object value)
putAll(Map map) - 删除:remove(Object key)
remove(Key k, Value v) - 修改:replace(Key k, newValue)
replace(Key k, oldValue, newValue) - 查询:get(Object key)
containsKey(Key k)
containsValue(Value v) - 遍历:keySet() —> 遍历key值,使用iterator或foreach
values() —> 遍历value值,使用iterator或foreach
entrySet() —> 遍历entry
6.4 内存结构说明(难点)
HashMap在jdk7中实现原理
- HashMap map = new HashMap():
在实例化以后,底层创建了长度是**16
**的一维数组Entery[] table
…可能执行过多次put…
map.put(key1, value1);- 首先调用key1所在类的hashCode()计算key1的哈希值,此时经过某种算法计算后,得到在Entry数组中的存放位置。
2.1 如果此位置上的数据为空,此时的key1-value1添加成功。 —> 情况1
2.2 如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据)(以链表形式存在)),比较key1和已经存在的一个或多个数据的哈希值:
2.2.1 如果key1的哈希值与已经存在的数据的哈希值不都相同,此时key1-value1添加成功。 —> 情况2
2.2.2 如果key1的哈希值和已经存在的某一个数据(key2-value2)的哈希值相同,继续比较:调用key1所在类的equals(key2)方法,比较:
2.2.2.1 如果equals()返回false:此时key1-value1添加成功。
2.2.2.2 如果equals()返回true:使用value1替换value2
- 补充:关于情况2和情况3:此时key1-value1和原来的数据以链表的方式存储。
- 在不断的添加过程中,会涉及到扩容的问题,当超出临界值(且要存放的位置非空)时,扩容。
- 默认的扩容方式:扩容为原来容量16的两倍,将原来的数据复制过来。
HashMap在jdk8中相较于jdk7在底层实现方面的不同
- new HashMap():底层没有创建一个长度为16的数组
- jdk 8 底层的数组是:Node[],而非Entry[]
- 首次调用put()方法时,底层创建长度为16的数组
- jdk7底层结构:数组+链表;jdk8底层结构:数组+链表+红黑树
- 形成链表时,七上八下(jdk7:新的元素指向旧的元素;jdk8:旧的元素指向新的元素)
- 当数组的某一个索引位置上的元素以链表形式存在的数据个数大于8且当前数组的长度大于64时,此时此索引位置上的所有数据改为红黑树存储。
HashMap底层典型属性的属性说明
DEFAULT_INITIAL_CAPACITY:HashMap的默认容量,16
DEFAULT_LOAD_FACTOR:HashMap的默认加载因子,0.75
threshold:扩容的临界值=容量×填充因子,16×75 => 12
TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树,8
MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量:64
LinkedHashMap的底层实现原理(了解)
- LinkedHashMap底层使用的结构与HashMap相同,因为LinkedHashMap继承于HashMap。
- 区别在于:LinkedHashMap内部提供了Entry,替换HashMap中的Node。
HashMap的源码分析
Map map = new HashMap();
for (int i = 0; i < 12; i++) {
map.put("i-" + i, i);
}
map.put("j-", 99);
//源码分析
/*
*/
6.5 TreeMap的使用
- 向TreeMap中添加key-value,要求key必须时由同一个类创建的对象
- 因为要照key进行排序:自然排序、定制排序
6.6 使用Properties读取配置文件
//Properties:常用来处理配置文件。key和value都是String类型
public static void main(String[] args) {
FileInputStream fis = null;
try {
Properties pros = new Properties();
fis = new FileInputStream("jdbc.properties");
pros.load(fis);//加载流对应的文件
String name = pros.getProperty("name");
String password = pros.getProperty("password");
System.out.println("name = " + name + ", password = " + password);
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
7 API总结
Collection接口