集合框架关系图
Java集合框架主要包括两种类型的接口:
1.集合(java.util.Collection)
存储一个元素集合,Collection接口又有3种子类型,List、Set和Queue,再下面是一些抽象类,然后是具体实现类;
Collection的实现类只能存储引用类型,所以对于基本数据类型,Collection的实现类只能存储他们的包装类(位于java.lang包)
Java中共有8个包装包
基本数据类型 byte short int long float double char boolean
包装类 Byte Short Integer Long Float Double Character Boolean
任何对象加入集合类后,如果集合没有使用泛型,会自动转变为Object类型,在取出的时候,需要进行强制类型转换;使用泛型之后不用强制类型转换。
1.1Set
Set接口的实现类存储的数据是无序的,元素不重复的。
package two;
import java.util.HashSet;
import java.util.Set;
public class Both1 {
public static void main(String[] args) {
Integer i=null;
//泛型 声明该集合中存储的元素类型
Set<Integer> set=new HashSet<Integer>();
//添加元素
set.add(1);
set.add(2);
set.add(3);
//移除元素
set.remove(2);
//集合的长度
int size=set.size();
System.out.println("长度="+size);
//清空集合
//set.clear();
//判断集合是否包含指定元素
boolean tar=set.contains(3);
System.out.println(tar);
set.add(3);
System.out.println("长度="+set.size());
for(Integer it:set){
System.out.println(it);
}
}
}
1.2List
List接口的实现类存储的数据是有序的,元素可以重复的。
List接口主要有两个实现类:ArrayList和LinkedList;
LinkedList与ArrayList的区别:
1.ArrayList是实现了基于动态数组的数据结构,在未声明长度的情况下,默认长度是10,数据填满会自动扩充原长度的50%。
2.LinkedList基于链表的数据结构。
3.对于随机访问get和set(即查找元素),ArrayList速度优于LinkedList,因为LinkedList要移动指针。
4.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
Vector:
1 基于动态数组的数据结构;
2 是线程同步;
3 数据填满时会自动扩充原长度的100%,因此ArrayList更节省空间;
package two;
import java.util.ArrayList;
import java.util.List;
public class Both2 {
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
//添加元素
list.add("a");
list.add("b");
list.add("a");
//集合长度
int size=list.size();
System.out.println(size);
//获取指定元素的第一个下标
int f_index=list.indexOf("a");
System.out.println(f_index);
//获取指定元素的最后一个下标
int l_index=list.lastIndexOf("a");
System.out.println(l_index);
//根据下标获取元素
String s=list.get(1);
System.out.println(s);
//替换指定下标位置的值
list.set(1, "abc");
for (String ss : list) {
System.out.print(ss+",");
}
}
}
2.Map(Java.util.Map)
Map中存储键值对(K-V)
HashMap是Map接口的实现类,该类根据键的hashcode值存储数据
Map的特点:
1.key和value只能是引用类型的数据
2.Map的key不允许重复,多次给同一个键名赋值,后面的会把前面的赋值覆盖
Map实现类 | KEY | VALUE |
HashMap | 允许为Null | 允许为Null |
TreeMap | 不允许为Null | 允许为Null |
ConcurrentMap | 不允许为Null | 不允许为Null |
HashTable | 不允许为Null | 不允许为Null |
package two;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/*
* Map
* Map中存储的元素是(K-V)键值对,键名key唯一
*
* Map的特点
* 1.key和value只能是引用类型的数据
* 2.Map的key不允许重复,多次给同一个键名赋值,后面的会把前面的赋值覆盖
*
* HashMap底层原理
* 1.数据结构是动态数组加链表,jdk1.8之后又加入了红黑树
* 2.当添加一个元素(key-value)时,首先计算元素的key的hash值,以此来确定插入数组中的位置
* 3.如果hash值相同,这是就添加到同一个hash值(hashCode)的元素的后面,他们在数组的同一位置,于是形成了链表
* 4.当链表长度大于8且元素(k-v)个数超过64时,链表就转换为红黑树,这样就提高了查找的效率
* 5.当红黑树中的节点个数小于等于64时,红黑树又重新转换为表
*/
public class Both4 {
public static void main(String[] args) {
Map<String,String> map=new HashMap<String,String>();
//添加键值对
map.put("name","hud1");
map.put("age","12");
map.put("name", "老李");
System.out.println(map);
//清空所有键值对
//map.clear();
//System.out.println(map);
//根据键名移除键值对
//map.remove("age");
//System.out.println(map);
String v=map.get("age");
System.out.println(v);
Set<String> keySet=map.keySet();
for (String k : keySet) {
System.out.println(map.get(k));
}
map.replace("name", "赵刚");
System.out.println(map);
int size=map.size();
System.out.println(size);
}
}
2.1 put()方法的实现原理
2.2 HashMap的实现原理
1.数据结构是动态数组加链表,jdk1.8之后又加入了红黑树
2.当添加一个元素(key-value)时,首先计算元素的key的hash值,以此来确定插入数组中的位置
3.如果hash值相同,这是就添加到同一个hash值(hashCode)的元素的后面,他们在数组的同一位置,于是形成了链表
4.当链表长度大于8且元素(k-v)个数超过64时,链表就转换为红黑树,这样就提高了查找的效率5.当红黑树中的节点个数小于等于64时,红黑树又重新转换为表
2.3 HashMap源码解释
默认初始容量=16 每次扩容必须是2的幂
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
构造函数中未指定时使用的扩容因子。
当一个map中存储的元素个数,超过map容量的75%时,触发扩容
static final float DEFAULT_LOAD_FACTOR = 0.75f;
最大容量,在两个带参数的构造函数中的任何一个隐式指定了更高的值时使用。
static final int MAXIMUM_CAPACITY = 1 << 30;//1073741824
树型阈值,当链表长度等于8时,链表转为红黑树
static final int TREEIFY_THRESHOLD = 8;
非树型阈值,当红黑树中元素长度等于6时,红黑树转为链表
static final int UNTREEIFY_THRESHOLD = 6;
最小树容量,当链表长度大于等于8且map中的元素(k-v)个数超过64时,链表就转换为红黑树
static final int MIN_TREEIFY_CAPACITY = 64;