集合是Java API所提供的一系列类,可以用于动态存放多个对象 (集合只能存对象)
集合类全部支持泛型,是一种数据安全的用法。
集合和数组的区别:
Map用于保存具有映射关系的数据,Map里保存着两组数据:key和value。Map 提供 key 到 value 的映射,你可以通过“键”查找“值”。
方法 | 描述 |
---|---|
void clear() | 移除该Map中的所有映射(清空) |
boolean containsKey(Object key) | 查询Map中是否包含指定key,如果包含则返回true |
boolean containsValue(Object value) | 查询Map中是否包含指定value,如果包含则返回true |
V put(K key, V value) | 将指定value与此映射中的指定key相关联。如果已经存在key,则旧value将被替换。(可用于添加、替换) |
void putAll(Map m) | 将所有映射从指定映射m复制到此映射 |
V get(Object key) | 返回指定key所对应的value,如Map中不包含key则返回null |
V getOrDefault(Object key, V defaultValue) | 通过key获取value,如果key不存在,返回默认值 |
boolean isEmpty() | 查询Map是否为空,如果空则返回true |
V putIfAbsent(K key,V value) | 如果指定的key没有对应的value(或value为null )将其与给定的value关联并返回null ,否则返回当前value。 |
V remove(Object key) | 如果key存在,则删除指定key的映射。并返回与key关联的value,如果key 不存在,则返回null |
boolean remove(Object key,Object value) | 仅当key与value匹配时,才删除指定key的条目,并返回true |
Collection |
返回该Map里所有value组成的Collection |
Set |
返回该Map中所有key所组成的set集合 |
Set |
返回Map中所包含的键值对所组成的Set集合,每个集合元素都是Map.Entry对象(Entry是Map的内部类)。 |
int size() | 返回该Map里的键值对的个数。 |
HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。
HashMap继承自AbstractMap类,实现了 Map 接口,根据键的 HashCode 值存储数据,具有很快的访问速度,不支持线程同步。(如果需要同步,可以用 Collections的synchronizedMap方法使HashMap具有同步的能力,或者使用ConcurrentHashMap)
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
HashMap最多只有一个key值为null,但可以有无数多个value值为null。
HashMap 是无序的,即不会记录插入的顺序。
HashMap底层数组长度必须为2的幂,这样做是为了hash准备,默认为16。
//创建HashMap对象
HashMap<String, Integer> map = new HashMap<>();
//添加
map.put("樱泽墨", 17);
map.put("更科瑠夏", 19);
map.put("一之濑千鹤", 19);
//将指定值与此映射中的指定键相关联。如果映射先前包含键的映射,则旧值将被替换。
//替换(返回原来的value) 返回与key关联的旧值,如果没有key的映射,则为null
Integer put = map.put("樱泽墨", 16);
System.out.println("返回与key关联的旧值:" + put);//17
//替换
map.replace("更科瑠夏", 17);//通过key替换value
map.replace("一之濑千鹤", 19, 18);//通过key+value替换value
//获取(通过key获取value)
Integer integer = map.get("樱泽墨");//返回指定Key映射到的值,如果此映射不包含Key的映射,则返回null 。
System.out.println("通过key获取value:" + integer);//16
//获取(通过key获取value,如果key不存在,返回默认值)
Integer orDefault = map.getOrDefault("哈尔卡拉", 666);
System.out.println("通过key获取value,如果key不存在,返回默认:" + orDefault);//666
System.out.println("判断此集合中是否包含某个Key:" + map.containsKey("樱泽墨"));//true
System.out.println("判断此集合中是否包含某个Value:" + map.containsValue(18));//true
System.out.println("判断此集合中是否没有元素:" + map.isEmpty());//true-没有元素 false-有元素
//将新集合中所有的元素添加到现有集合中
HashMap<String, Integer> newMap = new HashMap<>();
newMap.put("a", 10);
newMap.put("bb", 20);
map.putAll(newMap);
System.out.println(map);//{樱泽墨=16, bb=20, a=10, 更科瑠夏=17, 一之濑千鹤=18}
//添加
//如果集合中有key,就返回value,不替换原来的值
//如果集合中没有key,就返回null并添加
Integer putIfAbsent = map.putIfAbsent("中野三玖", 17);
System.out.println(putIfAbsent);//null
System.out.println(map);//{樱泽墨=16, bb=20, a=10, 更科瑠夏=17, 中野三玖=17, 一之濑千鹤=18}
//删除
map.remove("bb");//通过key删除映射关系
map.remove("a", 10);//通过key+value删除映射关系
System.out.println("获取映射关系的个数:" + map.size());//7
System.out.println(map);//{樱泽墨=16, 更科瑠夏=17, 中野三玖=17, 一之濑千鹤=18}
//获取所有的value值
Collection<Integer> values = map.values();
//集合-->数组-->字符串
System.out.println(Arrays.toString(values.toArray()));//[16, 17, 17, 18]
//keySet()遍历:将map集合中所有的key获取出,存放在Set集合中,遍历Set依次获取出key,就能获取到对应value
Set<String> keySet = map.keySet();
for (String key : keySet) {
Integer value = map.get(key);//返回指定Key映射到的值
System.out.println(key + " -- " + value);
}
//樱泽墨 -- 16
//更科瑠夏 -- 17
//中野三玖 -- 17
//一之濑千鹤 -- 18
//entrySet()遍历:将map集合中所有的映射关系(Entry)获取出,存放在Set集合中,遍历Set依次获取出Entry
Set<Entry<String, Integer>> set = map.entrySet();
for (Entry<String, Integer> entry : set) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + " -- " + value);
}
//清空集合
map.clear();
System.out.println(map);// {}
LinkedHashMap = HashMap + 双向链表
LinkedHashMap继承自HashMap,所以LinkedHashMap拥有HashMap的所有特性。
LinkedHashMap使用双向链表来维护键值对的次序,迭代顺序与键值对的插入顺序保持一致,性能低于HashMap
public class LinkedHashMap<K,V>
extends HashMap<K,V>
implements Map<K,V>
{...}
HashTable是较为远古的使用Hash算法的容器结构,现在基本已被淘汰,单线程转为使用HashMap,多线程使用ConcurrentHashMap。
Hashtable与 HashMap类似,继承自Dictionary类,不允许记录的键或者值为null
很多方法都是用synchronized修饰,支持线程同步( 线程安全 ),即任一时刻只有一个线程能写Hashtable,导致了 Hashtable在写入时会比较慢
HashTable底层数组长度可以为任意值,造成了hash算法散射不均匀,容易造成hash冲突,默认为11
public class Hashtable<K,V>
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable {...}
Properties 类是Java 语言的配置文件所使用的类。 Xxx.properties 为Java 语言常见的配置文件,以key=value 的 键值对的形式进行存储值,key值不能重复
public class Properties extends Hashtable<Object,Object> {...}
Properties的使用
src/DBConfig.properties
username = Miku
password = 12345
Test.java
public class Test {
public static void main(String[] args) throws IOException {
//创建Properties的对象
Properties p = new Properties();
//把配置文件加载到p对象中
p.load(Test01.class.getClassLoader().getResourceAsStream("DBConfig.properties"));
//load()从输入字节流中读取属性列表(键值对)
//getClassLoader()返回此对象表示的类或接口的类加载器
//getResourceAsStream()用于读取资源的输入流,如果找不到资源,则为null
//获取配置文件中数据
String username = p.getProperty("username");
//getProperty()在此属性列表中搜索具有指定键的属性。如果未找到将返回null
String password = p.getProperty("password");
System.out.println(username + " -- " + password);//Miku -- 12345
}
}
TreeMap实现了红黑树的结构,形成了一颗二叉树。能够把保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器。
TreeMap继承于AbstractMap,实现了Map, Cloneable, NavigableMap, Serializable接口。
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable {...}
特点:
TreeMap特殊方法
方法 | 描述 |
---|---|
Map.Entry firstEntry() | 返回最小key所对应的键值对,如Map为空,则返回null |
Map.Entry lastEntry() | 返回最大key所对应的键值对,如Map为空,则返回null |
Object firstKey() | 返回最小key,如果为空,则返回null |
Object lastKey() | 返回最大key,如果为空,则返回null |
Map.Entry higherEntry(0bject key) | 返回位于key后一位的键值对,如果为空,则返回null |
Map.Entry lowerEntry(0bject key) | 返回位于key前一位的键值对,如果为空,则返回null |
Object lowerKey (object key) | 返回位于key前一位key值,如果为空,则返回null |
TreeMap<String, Integer> treeMap = new TreeMap<>();
treeMap.put("c", 21);
treeMap.put("f", 10);
treeMap.put("a", 28);
treeMap.put("d", 8);
treeMap.put("b", 21);
Set<Entry<String, Integer>> entrySet = treeMap.entrySet();
for (Entry<String, Integer> entry : entrySet) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + " -- " + value);
}
//a -- 28
//b -- 21
//c -- 21
//d -- 8
//f -- 10
Entry<String, Integer> firstEntry = treeMap.firstEntry();
System.out.println("返回最小key所对应的键值对:" + firstEntry);//a=28
Entry<String, Integer> lastEntry = treeMap.lastEntry();
System.out.println("返回最大key所对应的键值对:" + lastEntry);//f=10
System.out.println("返回最小key:" + treeMap.firstKey());//a
System.out.println("返回最大key:" + treeMap.lastKey());//f
Entry<String, Integer> higherEntry = treeMap.higherEntry("b");
System.out.println("返回位于b后一位的键值对:" + higherEntry);//c=21
Entry<String, Integer> lowerEntry = treeMap.lowerEntry("c");
System.out.println("返回位于c前一位的键值对:" + lowerEntry);//b=21
TeeMap使用内置排序接口
需求:学生对象存在TreeMap key的位置,用年龄排序
Student.java
//实现Comparable接口
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
//重写compareTo()方法
@Override
public int compareTo(Student o) {
return this.age-o.age;
}
}
Test.java
TreeMap<Student, String> map = new TreeMap<>();
map.put(new Student("中野三玖", 17), "12138");
map.put(new Student("中野二乃", 18), "12137");
map.put(new Student("中野四叶", 16), "12139");
Set<Entry<Student, String>> entrySet = map.entrySet();
for (Entry<Student, String> entry : entrySet) {
Student key = entry.getKey();
String value = entry.getValue();
System.out.println(key + " -- " + value);
}
//Student [name=中野四叶, age=16] -- 12139
//Student [name=中野三玖, age=17] -- 12138
//Student [name=中野二乃, age=18] -- 12137
TreeMap使用外置排序接口
需求:学生对象存在TreeMap key的位置,先按照名字长度排序,长度一致按照年龄排序
TreeMap<Student, String> map = new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
if (o1.getName().equals(o2.getName()) && o1.getAge() == o2.getAge()) {
return 0;
}
if (o1.getName().length() != o2.getName().length()) {
return o1.getName().length() - o2.getName().length();
}
if (o1.getAge() != o2.getAge()) {
return o1.getAge() - o2.getAge();
}
return 1;
}
});
map.put(new Student("椎名真白", 18), "12137");
map.put(new Student("更科瑠夏", 17), "12138");
map.put(new Student("樱泽墨", 16), "12139");
Set<Entry<Student, String>> entrySet = map.entrySet();
for (Entry<Student, String> entry : entrySet) {
Student key = entry.getKey();
String value = entry.getValue();
System.out.println(key + " -- " + value);
}
//Student [name=樱泽墨, age=16] -- 12139
//Student [name=更科瑠夏, age=17] -- 12138
//Student [name=椎名真白, age=18] -- 12137
ConcurrentHashMap是HashMap的一个线程安全的、支持高效并发的版本。
public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
implements ConcurrentMap<K,V>, Serializable {...}
高效并发机制是通过以下保证的
ConcurrentHashMap读操作不需要加锁在于以下三点:
ConcurrentHashMap 采用了分段锁技术,其中 Segment 继承于 ReentrantLock。不会像 HashTable 那样不管是 put 还是 get 操作都需要做同步处理,理论上 ConcurrentHashMap 支持 CurrencyLevel (Segment 数组数量)的线程并发。每当一个线程占用锁访问一个 Segment 时,不会影响到其他的 Segment。
Collection 与 Map的区别
Collection 存单个值,可以获取迭代器进行遍历
Map存两个值(Key-Value),不可以获取迭代器,不能遍历(Map可以间接遍历)
理解Set为什么是无序
无序:存入顺序和取出顺序不一致,无序不等于随机
ArrayList 与 LinkedList的区别
使用上的区别:
LinkedList添加了
队列模式-先进先出(removeFirst())
栈模式-先进后出(removeLast())
效率上的区别:由于ArrayList底层数据结构是一维数组,LinkedList底层数据结构是双向链表
添加 - 不扩容的情况:ArrayList快
添加 - 扩容的情况:LinkedList快
注意: 工作中常用ArrayList,因为很多需求都需要使用查询功能,ArrayList查询更快
数据结构 | 是否有序 | 线程安全 | 能否存null | |
---|---|---|---|---|
ArrayList | 数组 | 有序 | 不安全 | 能 |
LinkedList | 链表 | 有序 | 不安全 | 能 |
Vector | 数组 | 有序 | 安全 | 能 |
HashSet | 哈希表 | 无序且唯一 | 不安全 | 能 |
LinkedHashSet | 链表+哈希表 | 有序且唯一 | 不安全 | 能 |
TreeSet | 二叉树(红黑树) | 自动排序且唯一 | 不安全 | 不能 |
HashMap | 哈希表 | 无序且key唯一 | 不安全 | key最多一个为null value可以多个为null |
LinkedHashMap | 链表+哈希表 | 有序且key唯一 | 不安全 | key最多一个为null value可以多个为null |
Hashtable | 哈希表 | 无序且key唯一 | 安全,效率低 | 不能 |
ConcurrentHashMap | 哈希表 | 无序且key唯一 | 安全,效率高 | 不能 |
TreeMap | 二叉树(红黑树) | 对Key排序且key唯一 | 不安全 | key不能为null (可通过自定义比较器) |
ArrayXxx:底层数据结构是数组,查询快,增删慢
LinkedXxx:底层数据结构是链表,查询慢,增删快
HashXxx:底层数据结构是哈希表。依赖两个方法:hashCode()和equals()
TreeXxx:底层数据结构是二叉树。两种方式排序:自然排序和比较器排序